07月26, 2017

常用Webpack2+优化要点

基于webpack自身配置的优化,不涉及到happypack和DLL.

总述

webpack自身是单进程的。优化的总思路是,时间上,小范围,扫描次数少;空间上,能分离即分离,能不打包不打包,在http请求数与文件大小之间找到平衡。

1.entry

根据指定目录下动态生成entry对象,可根据不同场景区分entry中的数量。间接提高开发效率。 或者遍历文件夹,生成entry对象。

let srcDir = path.resolve(process.cwd(), 'static/\$dev')
let componentsDir = path.resolve(process.cwd(), 'static/\$dev/components')

let entries = (() => {
    let entryFiles = (process.env.NODE_ENV === 'production')
? glob.sync(srcDir+"/+(index|service|tryout|app|user|stat|knowledge|doc|plan|tech|example|semservice|semutterance)/*.js")
                     : glob.sync(srcDir+"/+(index|semservice|semutterance|knowledge|app)/*.js")
    let map = {}
    entryFiles.forEach(function(filepath){
        let filename = filepath.substring(filepath.lastIndexOf('\/') + 1,filepath.lastIndexOf("."))
        map[filename] = filepath;
    });
    return map
}())

2.resolve

modules默认只包括node_modules,如果需要添加其他的目录,需要保证node_modules在最后一位。

resolve:{
    // 使用绝对路径,将只在给定目录中搜索。
    modules: [path.resolve(__dirname, "src"), "node_modules"],
    // 可省略文件后缀
    extensions: ['.js', '.vue'],
    // 减少webpack扫描时,每次查找相同包的时间。
    alias:{
        echarts:"components/echarts.min.js", // echarts
        citySelector:"components/citySelector.js" // 城市选择
    }
},

// 文件内引用时
import echarts from 'echarts';

3.module中的rules

总的来说就是,尽量添加include, exclude,限定范围。 在rules进行test时,尽量精准匹配,比如如果没有jsx的文件,只有js的,test就可以写为/.js$/,而不是/.jsx?$/。(具体正则匹配的效率上,没有实际验证过。。)

其中babel, babel对文件的编译时间是比较久的,里面东西比较多,这里简单说几点。 配置中可以开启cache,这样在文件没有修改的时候,babel不会重新编译,以节约时间。 另一个是,babel-pollyfilltransform-runtime

{
    test: /\.js$/,
  loader: 'babel-loader?cacheDirectory',
  include: [path.resolve(__dirname, "src")],
  exclude: [path.resolve(__dirname, "src", "assets"), /node_modules/]
}
.babelrc
{
  "presets": [
      [
          "es2015",
      {
          // 对modules语法不做转换,defaults to 'commonjs'
          "modules": false
      }],
      // 0 -> n, 0打包后的代码量最大。
      "stage-0"
  ],
  // 动态对babel不能转换的新的API进行‘填补’
  "plugins": ["transform-runtime"],
  "comments": false
}

4.module中的noParse

module{
    //忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制
    // noParse:[componentsDir]
    noParse:['jquery', 'lodash'],
    rules: [
        ....
    ]
}

5.只在production环境下的,tree-shaking

实际验证现阶段(2017.7.27)tree-shaking之后,文件大小变化并不明显。主要受写法限制。尤其是引用大量第三方非ES6写法的库,其实作用不是很大。如果是从头自己写,在遵循ES6标准的基础上,控制性更好些。 同时uglify本身时间还比较长。用时间换空间的性价比不高。

因为tree-shaking必须配置一些压缩插件才能实现,默认是使用webpack-uglifyJS,但是由于是单进程的,处理比较慢。可选用webpack-parallel-uglify-plugin,多核处理。

new UglifyJsparallelPlugin({
  cacheDir: '.cache/',
  workerCount: os.cpus().length,
  uglifyJS: {
      // 可以用uglifyJS自身的配置
      // 这里用于支持低版本IE
    supper_ie8: true,
    compress: {
        screw_ie8: false,
        properties: false,
        warnings: false
    },
    output: {
        screw_ie8: false,
        beautify: true,
        quote_keys: true
    },
    mangle: {
        screw_ie8: false
    },
    sourceMap: false
  }
})

6. 只在dev环境下

module.exports.devtool = '#cheap-module-eval-source-map';

7. 编译成es3

关于在IE低版本下运行,这里会遇到一些坑,另开一篇具体说说。

const es3ifyPlugin = require('es3ify-webpack-plugin');

好了,做完上述优化,你会发现时间上变化并不明显。。。其实最主要的还是需要DLL,拆分,分步。

webpack.optimize.CommonsChunkPlugin

entry中,
//需要配合下面的CommonsChunkPlugin才能把库文件从index中分类出来
vendor: ["vue", "vue-router", "axios"]

new CommonsChunkPlugin({
  name: 'vendor',
  filename: "vendor.js"
})

其他一些常用配置

package.json

npm run build

"scripts": {
    "dev": "webpack-dev-server --inline --hot --quiet --host 127.0.0.1 --port 8300",
    "build": "../node_modules/.bin/cross-env NODE_ENV=production DEBUG_ENV=online webpack --progress --hide-modules --colors --profile"
  },

查看打包后的文件大小

http://alexkuz.github.io/webpack-chart/ webpack --json --profile > stats.json

webpack-dev-server

与webpack -w 的区别 webpack -w 增量打包,在界面不会有任何体现,需要手动刷新。

webpack-dev-server,基于express的8080 Node服务器。可以设置代理等等。 具有HMR(热替换), LiveReload(自动刷新整个页面)。 实时编译,在内存中的。比webpack -w更快。 打包的静态资源路径相对于publicPath,如果devServer本身不设置,则相对于webpack的publicpath, 如果都不设置,则为'/'。

与下面的content-base没有关系,只是说页面里的静态资源从哪的路径访问的。

这里面有个content-base, 还没弄清楚干啥的??。。 content-base是webpack-dev-server的HTTP服务启动后的根目录。最直接的就是如何访问到那个index.html的途径,与其物理存放位置的关系。

本文链接:https://imjiaolong.cn/post/webpack2.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。