利用webpack搭建的前端工程化环境

随着webpack3.x的发布,其功能也越来越强大,很多的项目的编译打包工具也由gulp逐渐转移到webpack。最近因为项目重构考虑使用使用vue,同时想从原来的gulp切换到webpack,所以搭建了webpack-vue的前端脚手架工具,这里记录下搭建的过程中的要点。项目源码

1. 用yarn代替npm

npm是一款非常好的包管理工具,之前在用npm安装项目依赖的时候总会因为某些依赖包推出了新版本从而导致编译结果不一样的问题,这是因为在安装依赖的时候npm并没有锁定依赖包的版本号(npm5好像已经解决了这个问题),每次安装的时候总是获取最新的依赖包,导致编译结果不一样。用yarn安装依赖包可以完美的解决这个问题。

官网下载并安装yarn

在命令行中执行yarn -versions,若能输出版本号表示安装成功

2. 初始化生成package.json文件

执行yarn init,填写项目相关信息

3. 安装项目依赖包和开发依赖包

执行yarn add *** ,安装项目依赖包,添加--dev表示安装成开发依赖,具体安装的依赖包可查阅项目源码中package.json文件

4. 建立常用库配置文件并打包常用库文件

1. 新建webpack-dll.config.js文件

这个配置文件只要是用来打包库文件的,这里介绍下几个重点配置

output: {
    path: outputDir,
    filename: 'js/lib/[name].js',
    library: '[name]_library',
    /*libraryTarget: 'umd'*/
},

output中的library和libraryTarget是为了自定义打包后的文件以怎样的形式输出,这里采用默认的var形式

new webpack.DefinePlugin({
    'process.env': {
        NODE_ENV: JSON.stringify('production')
    }
}),

这里定义环境为开发环境,方便生成的库文件直接用于开发环境

 //稳定模块ID
new webpack.HashedModuleIdsPlugin(),

new webpack.DllPlugin({
    // 本Dll文件中各模块的索引,供DllReferencePlugin读取使用
    path: dll_manifest_name + '.json',
    //当前Dll的所有内容都会存放在这个参数指定变量名的一个全局变量下,注意与参数output.library保持一致
    name: '[name]_library',
    // 指定一个路径作为上下文环境,需要与DllReferencePlugin的context参数保持一致,建议统一设置为项目根目录
    context: __dirname,
})

这个是为了稳定模块ID并生成manifest文件,方便在生产环境中通过读取dll_manifest知道哪些文件已经被dll打包,而不需要再次打包

2. 生成库文件dll.js

执行 yarn dll,会在src/app/js/lib/文件夹下生成dll.js文件,该文件打包了vue2.5.13,axios0.17.1,flexible,webpack-zepto,具体要打包哪些文件可由webpack-dll.config.js中的entries来配置

若有必要可考虑生成dll.css

5. 建立配置文件

这里我将配置文件分为3个,一个基础配置文件,一个开发环境配置文件,一个生产环境配置文件,开发环境和生产环境配置文件通过webpack-merge插件调用基础配置文件。

基础配置文件webpack.base.js

在基础配置文件中包含了基本的配置信息,这里主要介绍下多页面配置中的htmlWebpackPlugin插件的使用。

var pages = getEntry(entryDir + '/html/**/*.ejs');
for (var pathname in pages) {
    var conf = {
        // html模板文件输入路径
        template: entryDir + '/html/' + pathname + '.js',
        // html文件输出路径
        filename: outputDir + '/html/' + pathname + '.html',
        inject: true,
        cache: true, //只改动变动的文件
        minify: {
            removeComments: true,
            collapseWhitespace: false
        }
    };
    //根据chunks提取页面js,css和公共verdors
    if (pathname in module.exports.entry) {
        conf.chunks = [pathname, 'vendors'];
    } else {
        conf.chunks = ['vendors'];
    }
    module.exports.plugins.push(new htmlWebpackPlugin(conf));
}

这里多页面配置采用的是ejs模板,通过循环入口文件,每个模板文件都配置一个htmlWebpackPlugin插件编译,最后达到生成多个页面的目的,通过chunks来提取页面的js/css/img等

开发环境配置文件webpack.dev.js

在开发环境配置文件,通过使用webpack-dev-server插件来建立一个静态服务器提供服务

devServer: {
    //设置服务器主文件夹,默认情况下,从项目的根目录提供文件
    contentBase: outputDir,
    //自动开启默认浏览器
    //open: true,
    //开启热模块替换,只重载页面中变化了的部分
    //hot: true,
    //hotOnly:true,
    //开启gzip压缩
    compress: true,
    //使用inlilne模式,会触发页面的动态重载
    inline: true,
    //当编译错误的时候,网页上显示错误信息
    overlay: {
        warnings: true,
        errors: true
    },
    //浏览器自动打开的文件夹
    //openPage: 'html/',
    //只在shell中展示错误信息
    //stats: 'errors-only',
    //设置域名,默认是localhost
    host: 'localhost',
    port: 8080
},

在使用热更新时需要使用热更新插件

//热模块替换插件
new webpack.HotModuleReplacementPlugin()

生产环境配置文件webpack.prod.js

在生产环境中我们需要关注公共组件的分离,代码压缩,文件缓存等问题,在公共组件分离时通过读取dll_manifest文件知道哪些文件不用打包,从而减少打包后的文件大小

new webpack.HashedModuleIdsPlugin(),
new webpack.DllReferencePlugin({
    // 指定一个路径作为上下文环境,需要与DllPlugin的context参数保持一致,建议统一设置为项目根目录
    context: __dirname,
    // 指定manifest.json
    manifest: require('../' + dll_manifest_name + '.json'),
    // 当前Dll的所有内容都会存放在这个参数指定变量名的一个全局变量下,注意与DllPlugin的name参数保持一致
    name: 'dll_library',
}),

在考虑代码压缩时通过使用以下配置

//压缩css代码
new OptimizeCssAssetsPlugin({
    assetNameRegExp: /\.css\.*(?!.*map)/g, //注意不要写成 /\.css$/g
    cssProcessor: require('cssnano'),
    cssProcessorOptions: {
        discardComments: { removeAll: true },
        // 避免 cssnano 重新计算 z-index
        safe: true
    },
    canPrint: true
}),
//提取css
new ExtractTextPlugin('css/[name].css?v=[contenthash:8]'),
//压缩JS代码
new webpack.optimize.UglifyJsPlugin({
    compress: {
        warnings: false
    },
    output: {
        comments: false,
    }
}),

在考虑线上文件缓存问题时可以使用以下配置

output: {
    //publicPath: 'http://localhost:8080/',
    filename: 'js/[name].js?v=[chunkhash:8]'
},

这里建议使用chunkhash,使用hash每次编译都会变化

至此配置以基本完成,目前仍有一些不足之处,一直在改进。源码src/app/文件夹下有一demo,大家可参考demo愉快的进行开发了,有问题欢迎评论提出

参考文献
  1. webpack官方文档,
  2. Webpack的dll功能,
  3. 详解webpack中的hash、chunkhash、contenthash区别