webpack打包优化

webpack是react项目标配的打包工具,和NPM搭配起来使用管理模块实在非常方便。
  webapck 把所有的静态资源都看做是一个 module,通过 webpack,将这些 module 组成到一个 bundle 中去,从而实现在页面上引入一个 bundle.js,来实现所有静态资源的加载。

定位 Webpack 速度慢的原因

打包的命令webpack后加三个参数:

  • --colors 输出结果带彩色,比如:会用红色显示耗时较长的步骤
  • --profile 输出性能数据,可以看到每一步的耗时
  • --display-modules 默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块

从命令行的结果里具体分析速度慢的原因。

通过Resolve设置,提高模块分析依赖的速度

resolve主要是用来配置解析模块路径和分析依赖,可以让require模块的定位更快。
1.resolve.alias别名是 Webpack 的一个配置项,它的作用是把用户的一个请求重定向到另一个路径 。如果在alias中定义了值,然后在代码中require该值的时候,会重定向到alias指定的位置。
关于alias的使用,官网给出了具体例子。不同的alias设置,在/abc/entry.js中使用require的效果:

alias不同设置的使用.png

2.resolve.rootresolve.modulesDirectories
root是通过绝对路径的方式来定义查找模块的文件夹。可以是一个数组,主要是用来增加模块的搜寻位置使用的。

这里root的值必须是绝对路径,使用path.resolve设置。
var path = require('path');
// ...
resolve: {
     root: [ 
       path.resolve('./app/modules'), 
       path.resolve('./vendor/modules') 
     ]
}
这样设置后,会增加搜索app/modules和vendor/modules下所有node_modules里面的模块。

modulesDirectories是用来设置搜索的目录名的,默认值:["web_modules", "node_modules"]。如果把值设置成["mydir"]
, webpack会查询 “./mydir”, “../mydir”, “../../mydir”等。

注意: Passing"../someDir","app","."or an absolute path isn’t necessary here. Just use a directory name, not a path. Use only if you expect to have a hierarchy within these folders. Otherwise you may want to use theresolve.root
option instead.

root和modulesDirectories的设置.png

配置module.noParse

module.noParse是webpack的另一个很有用的配置项,如果你 确定一个模块中没有其它新的依赖就可以配置这项,webpack将不再扫描这个文件中的依赖。

module: { 
    noParse: [/moment-with-locales/] 
}

配置Loader的exclude或include来设定babel的使用范围

对于很多的 npm 包来说,他们完全没有经过 babel 的必要(成熟的 npm 包会在发布前将自己 es5,甚至 es3 化),让这些包通过 babel 会带来巨大的性能负担。
使用 exclude,屏蔽掉 npm 里的包,从而使整包的构建效率飞速提高。

module: {
   loaders: [ { 
     test: /\.js(x)*$/, 
     loader: 'babel-loader', 
     exclude: function(path) { 
         // 路径中含有 node_modules 的就不去解析。 
         var isNpmModule = !!path.match(node_modules/); 
         return isNpmModule;
    }, 
    query: { 
        presets: ['react', 'es2015-ie', 'stage-1']
    } 
  } ]
}

甚至,在十分确信的情况下,使用 include 来限定 babel 的使用范围,进一步提高效率。

module: { 
    loaders: [ { 
       test: /\.js(x)*$/,
       loader: 'babel-loader',
       include: [  
          // 只去解析运行目录下的 src 和 demo 文件夹 
          path.join(process.cwd(), './src'), 
          path.join(process.cwd(), './demo') 
       ], 
       query: { 
           presets: ['react', 'es2015-ie', 'stage-1'] 
       } 
    } ] 
}

使用externals,把不需要打包的模块排除在外

Webpack 可以配置 externals来将依赖的库指向全局变量,从而不再打包这个库。在页面上引入 Web 上的公用 CDN 服务。

webpack中配置:
     externals: { moment: true }

页面html上引入script:
<script src="//apps.bdimg.com/libs/moment/2.8.3/moment-with-locales.min.js"></script>

等于让 Webpack 知道,对于 moment这个模块就不要打包啦,直接指向 window.moment就好。不过别忘了加载moment-with-locales.min.js,让全局中有 moment这个变量。

使用DLL & DllReference

除了正在开发的源代码之外,通常还会引入很多第三方 NPM 包,这些包我们不会进行修改,但是仍然需要在每次 build 的过程中消耗构建性能,那有没有什么办法可以减少这些消耗呢?DLLPlugin 就是一个解决方案,他通过前置这些依赖包的构建,来提高真正的 build 和 rebuild 的构建效率。
首先,我们来写一个 DLLPlugin 的 config 文件。定义webpack-dll-config.js文件:

const path = require('path'); 
const webpack=require('webpack');

const vendors=[
    'react',
    'react-dom',
    'react-router',
    'history',
    'immutable',
    'redux',
    'react-redux',
    'redux-router',
    'redux-thunk',
    'moment',
    'es6-promise',
    'whatwg-fetch',
    'lodash'
];

module.exports={
    entry:{
        'vendor':vendors,
    },
    output:{
        path:path.join(__dirname, 'dist'),
        filename:'[name].dll.js',//[name]的部分由entry的名字替换
        /**
         * output.library
         * 将会定义为 window.${output.library}
         * 在这次的例子中,将会定义为`window.vendor_library`
         */
        library:'[name]_library',
    },
    plugins:[
        new webpack.DllPlugin({
            /**
             * path 定义 manifest 文件生成的位置
             */
            path:'manifest.json',
            /**
             * name 是dll暴露的对象名,要跟 output.library 保持一致;
             * dll bundle 输出到那个全局变量上
             */
            name: '[name]_library',
            context:__dirname //是解析包路径的上下文,这个要跟接下来配置的 webpack.config.js 一致。
        })
    ]
}

执行 命令【webpack --config webpack-dll-config.js 】就会在 dist 目录下生成 dll bundle 和在根目录生成对应的 manifest文件。manifest 文件的格式大致如下,由包含的 module 和对应的 id 的键值对构成。

接下来通过 DLLReferencePlugin 来使用刚才生成的 DLL Bundle。在默认的webpack-config.js中添加plugins:

new webpack.DllReferencePlugin({
      context: __dirname,//context 需要跟dll中的保持一致,这个用来指导 Webpack 匹配 manifest 中库的路径;
      manifest: require('./manifest.json')
    }),

最后在页面中要引入两个js

<body> 
    <script src="dist/vendor.dll.js"></script> 
    <script src="dist/bundle.js"></script>
</body> 

使用DLL这样的方式的可以把第三方包和自己的代码包分离,有修改也只需要发布自己的代码包。

关于优化插件OPTIMIZATION

  webpack 提供了一些可以优化浏览器端性能的优化插件,如UglifyJsPlugin,OccurrenceOrderPlugin 和 DedupePlugin,都很实用,也都在消耗构建性能(UglifyJsPlugin 非常耗性能),如果你是在开发环境下,这些插件最好都不要使用,毕竟脚本大一些,跑的慢一些这些比起每次构建要耗费更多时间来说,显然还是后者更会消磨开发者的耐心,因此,只在正产环境中使用 OPTIMIZATION。

CommonsChunkPlugin

  当你的 webpack 构建任务中有多个入口文件,而这些文件都 require 了相同的模块,如果你不做任何事情,webpack 会为每个入口文件引入一份相同的模块,显然这样做,会使得相同模块变化时,所有引入的 entry 都需要一次 rebuild,造成了性能的浪费,CommonsChunkPlugin 可以将相同的模块提取出来单独打包,进而减小 rebuild 时的性能消耗。
  同时将多个入口文件相同的js打包处一个共同的后,也可以利用缓存,使加载第二页面的时候不需要再加载共同文件。

commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common', 'common.[hash].js');
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容