资讯专栏INFORMATION COLUMN

webpack搭建多页面系统(三) 理解webpack.config.js的四个核心概念

邹强 / 1322人阅读

摘要:关于模板的有好几种。一次安装所有的大家可以了解一些的用法把编译成。安装参考文档功能将源文件迁移到指定的目录,返回新的文件路径。安装用法它会将所有的入口中引用的移动到和页面对应的独立分离的文件。

webpack是需要自己编写自己需要的一个配置对象,取决你如何使用webpack,下面指定了所有的可用的配置选项。
参考文档:https://doc.webpack-china.org...

webapck.config.js

var path = require("path"); #使用Node内置的path模块,并在它前面加上__dirname这个全局变量。可以防止
不同操作系统之间的文件路径问题,并且可以使用相对路径按照预期工作。
var webpackConfig = {
    devtool:"inline-source-map", //开发错误提示,嵌入到源文件
    entry:{ },  //string | object | array ;这里应用程序开始执行;webpack开始打包
    output:{ },  //webpack 如何输出结果的相关选项
    devServer:{ },  //开发服务器配置,
    module:{         //关于模块配置
        rules:[]     //模块规则(配置loader、解析器等选项)
    },
    plugins:plugins, //附加插件列表
}
module.exports = webpackConfig;
1、entry参数:入口文件配置
entry: //string | array | object。入口文件是应用程序的起点入口,从这里应用程序启动执行。如果传递的是一个数组,
        那么数组的每一项都会执行。
规则:每个HTML页面都有一个入口起点。单页应用(SPA):一个入口起点;多页应用(MPA):多个入口起点。
命名:如果传入一个字符串或字符串数组,chunk会被命名为main。如果传入一个对象,则每一个键(key)是chunk的名称,
        该值描述了chunk的入口起点。


在我的配置中,由于是对多页面的处理,所以采用entry:object;每一个键(key)是chunk的名称,同时又是chunk的入口起点。

webpack.config.js

//glob在webpack中对文件的路径处理
var glob = require("glob");
const HtmlWebpackPlugin = require("html-webpack-plugin")
var webpackConfig = {
    /*webpack基础配置*/
};    
//封装方法,获取指定路径下的入口文件
//返回的结构 [ "src/pages/contact/contact/index.js",
//            "src/pages/index/index/index.js",
//            "src/pages/join/join/index.js",
//            "src/pages/pagea/index/index.js" ]
function getEntries(globPath){
    //方法: glob.sync(pattern,[options]);该方法成功后,返回匹配搜索之后的数组,
    //没有匹配返回一个空数组;pattern:"src/pages/**/index.js";这里‘**’匹配模式表示的是
    位于src/pages/和/index.js的这两层文件名
    var files = glob.sync(globPath),
    entries = {};
    files.forEach(function(filepath){
        //取倒数第二层(pages下面的文件夹)做包名
        var split = filepath.split("/");
        var name = split[split.length - 2];
        
        entries[name] = "./" + filepath;
    });
    return entries;
};
//
var entries = getEntries("src/pages/**/index.js");
Object.keys(entries).forEach(function(name){
    //这里循环输出每一个页面的entry,
    webpackConfig.entry[name] = entries[name];
    //判断是否是登陆页面;因为登陆页面和其他页面是两个不同的模板
    //HtmlWebpackPlugin插件的详细用法参考:https://segmentfault.com/a/1190000007294861
    if(name == "login/login"){
        var plugin = new HtmlWebpackPlugin({
            //有模板生成的html文件名
            filename:"login.html",
            //登陆页面的html模板
            template:"./src/login.html",
            inject:"body",
            chunks:["commons",name]
        });
    }else{
        var plugin = new HtmlWebpackPlugin({
            //有模板生成出来的html文件名
            filename:name + ".html",
            //除登陆页面外,多个页面使用同一个模板
            template:"./src/index.tmpl.html",
            inject:"body",
            chunks:["commons",name]
        })
    }
})
2、output参数:输出文件配置

output包括一组选项,指示webpack如何去输出、以及在哪里输出你的(bundle、asset和其他你所打包或使用webpack载入的任何内容)。
常用的参数path、publicPath、filename、chunkFilename.
在我的webpack.config.js的配置中:
webpack.config.js:

    var webpackConfig = {
        devtool:"inline-source-map",
        entry:{ },
        output:{
            path:__dirname + "build",
            filename: "js/[name].bundle-[chunkhash:8].js"
        },
        devServer:{ },
        module:{
            rules:rules
        },
        plugins:plugins
    }

output.path:string;output目录对应一个绝对路径 #path:path.resolve(__dirname,"bulid")
output.filename:string;此选项决定了每一个输出bundle的名称。这些bundle将写入到output.path选项指定的目录下。
两种情况:
1、对于单入口起点,filename会是一个静态名称。filename:"bundle.js"。
2、对于多入口起点、代码拆分或各种插件创建多个bundle,应该使用以下四种方式:

 (a)使用入口名称:  filename:"[name].bundle.js";
 (b)使用内部chunk id : filename:"[id].bundle.js";
 (c)使用每次构建过程中,唯一的hash生成:filename:"[name].[hash].bundle.js";
 (d)使用基于每个chunk内容的hash: filename:"[chunkhash].bundle.js";

这里涉及到缓存的知识:参考文档:https://doc.webpack-china.org...
可以通过命中缓存的技术,以降低网络流量,使网站加载速度更快,如果我们在部署新版本时不更改资源的文件名,浏览器就可能认为它没有更新,就会使用它的缓存版本,通过必要的配置,以确保webpack编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件。
输出文件的文件名(output.filename):
通过使用output.filename的不同的方式,可以确保浏览器获取修改后的文件。文档中建议使用[chunkhash]替换,在文件名中包含一个chunk相关的哈希。

3、常用loader(加载器)配置:module参数

Loaders的常用的加载器,参考文档:https://doc.webpack-china.org...
安装相对应的loader:

npm install --save-dev css-loader;作用是指示webpack对每个.css使用css-loader

使用Loader的方法:

在应用程序中,有三种使用loader的方式:
1、配置(推荐):在webpaack.config.js文件中指定loader。
2、内联:在每个import 语句中显示指定loader。
3、CLI: 在shell命令中指定它们。
配置[Configuration]:
    module.rules允许你在webpack配置中指定多个loader。这是展示loader的一种简明方式,有助于使代码变得简洁。
    这是我经常用的书写方式。
    module:{
        rules:[
            {
              test:/.css$/,
              use:[
                  { loader: "style-loader" },
                  {
                    loader:"css-loader",
                    options{
                        modules:true
                    }
                  }
              ]
            }
        ]
    }

下面介绍一些常用的loader的用法:

1、html-loader

html-loader 导出HTML为字符串,需要引用静态资源。
关于模板(templating)的有好几种:html-loader、pug-loader、jade-loader、markdown-loader、posthtml-loader、react-markdown-loader、handlebars-loader、markup-inline-loader。

只介绍html-loader的使用:
参考文档:https://doc.webpack-china.org/loaders/html-loader
安装:
    npm install --save-dev html-loader
用法:
    默认情况下,每个本地的都需要require(require(./image.png))来进行加载。
    不过这需要file-loader或url-loader(这个后面有介绍)。
示例:
    module:{
        rules:[{
            test:/.html$/,        #匹配以‘.html’结尾的模块;
            loader:"html-loader",  #html-loader加载器
            options:{              #可选项(一般用于上线的webpack.build.config中)
                minimize: true,            #Boolean: 是否压缩html
                removeComments: true,      #Boolean: 是否删除注释  
                collapseWhitespace: true, #Boolean: 是否删除空格  
            }
        }]
    }
    
2、babel-loader

babel-loader 加载es2015代码,并且将代码转译为ES5
参考文档:https://doc.webpack-china.org...

安装:
npm install --save-dev babel-loader babel-core babel-preset-env
用法:
在webpack配置对象中,需要添加babel-loader到module的loader列表中,像下面这样:
module:{
    rules:[
        {
            test:/.js$/,          #匹配以‘.js’结尾的文件
            loader:"babel-loader", #babel-loader加载器
            include:path.resolve(__dirname,"src"),   #只包括src 
            exclude:path.resolve(__dirname,"node_modules"), #排除node_module
            query:{
                presets:["preset-env"]
            }
        }
    ]
}
babel-loader编译很慢的,为了确保转译尽可能少的文件,可能使用/.js$/来匹配,排除node_modules,配置exclude选项,
提高编译速度。
3、less/css-loader

less/css-loader是对css的处理,下面分别介绍处理css时,用到的css-loader、less-loader、style-loader、postcss-loader。这几种loader配合使用。
一次安装所有的loader:
npm install --save-dev autoprefixer css-loader less-loader style-loader postcss-loader
less-loader:

大家可以了解一些less的用法:http://less.bootcss.com/
less-loader: 把less编译成css。使用css-loader或者raw-loader把它变成一个JS模块,
并使用ExtractTextPlugin把它解压到一个多带带的文件中,
这样你的样式不依赖于JavaScript。另外,less-loader并不会针对url()语法做特别的转换,
如果想把url()语句里涉及的文件(比如图片、字体文件)也一并用webpack打包的话,就必须利用css-loader进一步处理。
参考文档:https://doc.webpack-china.org/loaders/less-loader/
用法:
将css-loader、style-loader、less-loader链式调用,使用ExtractTextPlugin把它解压到多带带的文件
webpack.config.js:
    const ExtractTextPlugin = require("extract-text-webpack-plugin");
    plugin = [...
     new ExtractTextPlugin("css/[name]-[chunkhash:8].css",{allChunks:false}), //css分离和压缩
     ...
    ];
    module:{
        rules:[
            {
                text:/.less$/,
                use:ExtractTextPlugin.extract({
                    fallback:"style-loader",
                    use:[
                        {
                            loader:"css-loader",
                            options:{
                                minimize:false;    #是否对css进行压缩
                            }
                        },
                        {
                            loader:"postcss-loader", #自动添加浏览器前缀
                        },
                        {
                            loader:"less-loader"
                        }
                    ]
                })
            }
        ]
    }

css-loader:

用法:
css-loader解释@import 和 url(),在import/require()后再解析它们。
选项:
    参考文档:https://doc.webpack-china.org/loaders/css-loader/
    常用的就是是否对css进行代码压缩(Minification):minimize:Boolean;还有就是对url()语句的处理。
    在less/css里url()语句,一般使用相对路径的方式来指定文件路径;请不要使用‘/’开头
    (即相对于网站的根目录,因为对于文件系统来说,这令人混淆)。

style-loader:

 用法:
 通过注入