{"componentChunkName":"component---src-templates-blog-post-js","path":"/2019/08/08/【webpack配置】一、常用基础插件🎉/","result":{"data":{"content":{"edges":[{"node":{"id":"9cc10200-df39-568b-a59b-5a05e0a78723","html":"<h2 id=\"初始化目录\" style=\"position:relative;\"><a href=\"#%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9B%AE%E5%BD%95\" aria-label=\"初始化目录 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>初始化目录</h2>\n<ol>\n<li>yarn init -y</li>\n<li>yarn add webpack webpack-cli webpack-dev-server --dev</li>\n<li>根目录初始化一个html, 加入一个id为app的div节点（为了之后react挂载）</li>\n<li>创建src/index.js.</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> _ <span class=\"token keyword\">from</span> <span class=\"token string\">'lodash'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> _<span class=\"token punctuation\">.</span>join<span class=\"token punctuation\">;</span></code></pre></div>\n<ol start=\"5\">\n<li>package.json中加入脚本配置。笔者机器上目前的npm版本为3.x.x，5.2以上的npm版本也可以使用npx命令。</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token string\">\"build:dev\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"rm -rf dist &amp;&amp; ./node_modules/.bin/webpack --mode development\"</span><span class=\"token punctuation\">,</span>\n<span class=\"token string\">\"build\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"rm -rf dist &amp;&amp; ./node_modules/.bin/webpack --mode production\"</span></code></pre></div>\n<ol start=\"6\">\n<li>分别执行两个脚本，发现dev模式产出size为552kb,prod模式为70.6kb，生产环境进行了代码压缩混淆。我们在index.js里加一行console.log(process.env.NODE<em>ENV)，打包后执行node dist/main.js，可以发现process.env.NODE</em>ENV变量已被注入到脚本执行环境的全局变量中。</li>\n</ol>\n<h2 id=\"webpack配置文件\" style=\"position:relative;\"><a href=\"#webpack%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6\" aria-label=\"webpack配置文件 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>webpack配置文件</h2>\n<p>为了更细粒化定制打包工具，我们需要手写webpack配置以支持生产环境。先定一个小目标，让我们输出一个支持react组件的html页面。</p>\n<ol>\n<li>yarn add @babel/core @babel/polyfill @babel/preset-env @babel/preset-react babel-loader --dev</li>\n<li>写一个简单的组件</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">    <span class=\"token keyword\">import</span> React <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom'</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span>join<span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'lodash'</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Comp</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token string\">'Hello'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'webpack'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> <span class=\"token string\">' '</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n    \n    ReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>Comp <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">,</span>\n        document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'app'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<ol start=\"3\">\n<li>webpack配置如下，其中entry和path注释的为webpack默认值。我们基于contenthash输出output，引入了preset-env插件兼容new ES syntax，使用preset-react兼容JSX。</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// entry: path.resolve(__dirname, 'src/index.js'),</span>\n    output<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// path: path.resolve(__dirname, 'dist')</span>\n        filename<span class=\"token operator\">:</span> <span class=\"token string\">'[name].[contenthash].js'</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    plugins<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n        <span class=\"token keyword\">new</span> <span class=\"token class-name\">HtmlWebpackPlugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            template<span class=\"token operator\">:</span> <span class=\"token string\">'index.html'</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// 将模版写入output path</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    module<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        rules<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n            <span class=\"token punctuation\">{</span>\n                test<span class=\"token operator\">:</span> <span class=\"token regex\">/\\.m?js$/</span><span class=\"token punctuation\">,</span>\n                exclude<span class=\"token operator\">:</span> <span class=\"token regex\">/node_modules/</span><span class=\"token punctuation\">,</span>\n                use<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n                    loader<span class=\"token operator\">:</span> <span class=\"token string\">'babel-loader'</span><span class=\"token punctuation\">,</span>\n                    options<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n                        presets<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'@babel/preset-env'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'@babel/preset-react'</span><span class=\"token punctuation\">]</span>\n                    <span class=\"token punctuation\">}</span>\n                <span class=\"token punctuation\">}</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">]</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    devServer<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        contentBase<span class=\"token operator\">:</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span>__dirname<span class=\"token punctuation\">,</span> <span class=\"token string\">'dist'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        compress<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n        port<span class=\"token operator\">:</span> <span class=\"token number\">9000</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>执行webpack-dev-server，我们将在9000端口看到输出。</p>\n<h3 id=\"split-chunks\" style=\"position:relative;\"><a href=\"#split-chunks\" aria-label=\"split chunks permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>split Chunks</h3>\n<p>我们利用optimization对打包出的main.js进行拆分。</p>\n<ol>\n<li>首先加入runtimeChunk，可以看到有6.12Kb的webpack runtime被提取了出来，这部分代码是webpack用来进行模块解析时所需要的。这样，当我们hash模块变更时，runtime所包含的模块信息清单就会单独更新。</li>\n<li>效果依然不明显，我们接下来配置splitChunks。</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">splitChunks<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    chunks<span class=\"token operator\">:</span> <span class=\"token string\">'all'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// async只作用于异步模块，all针对所有模块，initial对同步模块生效</span>\n    minSize<span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 合并前模块文件大小</span>\n    minChunks<span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 最小被引用次数</span>\n    automaticNameDelimiter<span class=\"token operator\">:</span> <span class=\"token string\">'-'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 命名链接符</span>\n    cacheGroups<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>  <span class=\"token comment\">// 设置缓存chunk</span>\n        vendors<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n            test<span class=\"token operator\">:</span> <span class=\"token regex\">/[\\\\/]node_modules[\\\\/]/</span><span class=\"token punctuation\">,</span>\n            minChunks<span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n            priority<span class=\"token operator\">:</span> <span class=\"token operator\">-</span><span class=\"token number\">10</span> <span class=\"token comment\">// 优先级更高</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token keyword\">default</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n            test<span class=\"token operator\">:</span> <span class=\"token regex\">/[\\\\/]src[\\\\/]js[\\\\/]/</span><span class=\"token punctuation\">,</span>\n            minChunks<span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 非第三方，被引用两次以上</span>\n            priority<span class=\"token operator\">:</span> <span class=\"token operator\">-</span><span class=\"token number\">20</span><span class=\"token punctuation\">,</span>\n            reuseExistingChunk<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token comment\">// 复用已有模块</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></code></pre></div>\n<p>修改后的开发环境打包结果如下：</p>\n<table>\n<thead>\n<tr>\n<th>Asset</th>\n<th>Size</th>\n<th>Chunks</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>index.html</td>\n<td>450 bytes</td>\n<td></td>\n</tr>\n<tr>\n<td>main.d4c9204ebd45eed48786.js</td>\n<td>3.39 KiB</td>\n<td>main</td>\n</tr>\n<tr>\n<td>runtime.acfdeda3904d25c72cbb.js</td>\n<td>6.12 KiB</td>\n<td>runtime</td>\n</tr>\n<tr>\n<td>vendors-main.804e8227ca2da7b727a5.js</td>\n<td>1.91 MiB</td>\n<td>vendors-main</td>\n</tr>\n</tbody>\n</table>\n<p>可以看到，vendors即node_modules按我们的命名规则被提出来了。并且业务代码只有3.39Kb，这样我们每次修改代码时只会更新这3.39Kb的文件，大大提高了打包速度。</p>\n<ol start=\"3\">\n<li>在production模式，minimize默认为true会进行压缩混淆代码，我们也可以用uglifyJS实现定制。</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">new</span> <span class=\"token class-name\">UglifyJsPlugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    exclude<span class=\"token operator\">:</span> <span class=\"token regex\">/\\.min\\.js$/</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 已压缩文件不再处理</span>\n    cache<span class=\"token operator\">:</span> <span class=\"token string\">'.cache'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 缓存文件夹</span>\n    parallel<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 多进程</span>\n    sourceMap<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    extractComments<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    uglifyOptions<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        compress<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n            unused<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n            drop_debugger<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n            collapse_vars<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n            reduce_vars<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        output<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n            comments<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span> <span class=\"token comment\">// 不输出注释</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"dynamic-import\" style=\"position:relative;\"><a href=\"#dynamic-import\" aria-label=\"dynamic import permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>dynamic import</h3>\n<p>让我们添加一个promisePolyfill，并通过一个btn click动态引入它。</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token string\">'@babel/polyfill'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Comp</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">onClick</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">e</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">asyncModule</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span>\n            <span class=\"token keyword\">await</span> <span class=\"token keyword\">import</span><span class=\"token punctuation\">(</span><span class=\"token comment\">/* webpackChunkName: \"promise\" */</span> <span class=\"token string\">'./promisePolyfill'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token function\">asyncModule</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">res</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>res<span class=\"token punctuation\">.</span>PromisePolyfill<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token string\">'Hello'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'webpack'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> <span class=\"token string\">' '</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>onClick<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>Click me and look at your console<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>其中babel-polyfill的引入是为了支持async/await需要的regeneratorRuntime。webpack使用require.ensure标记异步模块，并通过window.webpackJsonp连接chunk文件。所以当我们调用import函数时，webpack使用一种类似jsonp的方式在文档头部动态添加script标签，再通过webpackJsonpCallback把异步函数加载到主文件供之后调用。\n打开DevTools Network我们可以看到，当我们点击按钮之后，promise脚本才开始下载，并且不会多次重复下载。</p>\n<h3 id=\"dll-config\" style=\"position:relative;\"><a href=\"#dll-config\" aria-label=\"dll config permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>dll config</h3>\n<p>dll plugin用于将第三方模块打包到动态链接库中，二次加载时参考dll从打包好的一个js中获得模块。</p>\n<ol>\n<li>我们再写一个webpack配置输出dll缓存文件。</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> webpack <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'webpack'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> path <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'path'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span>CleanWebpackPlugin<span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'clean-webpack-plugin'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">// dll文件存放的目录</span>\n<span class=\"token keyword\">const</span> dllPath <span class=\"token operator\">=</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span>__dirname<span class=\"token punctuation\">,</span> <span class=\"token string\">'./dll'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nmodule<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    entry<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// 把react, lodash放到一个单独的动态链接库</span>\n        react<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'react'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'react-dom'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'lodash'</span><span class=\"token punctuation\">]</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    output<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        filename<span class=\"token operator\">:</span> <span class=\"token string\">'[name]-[hash].dll.js'</span><span class=\"token punctuation\">,</span>\n        path<span class=\"token operator\">:</span> dllPath<span class=\"token punctuation\">,</span>\n        library<span class=\"token operator\">:</span> <span class=\"token string\">'_dll_[name]'</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    plugins<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n        <span class=\"token keyword\">new</span> <span class=\"token class-name\">CleanWebpackPlugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token keyword\">new</span> <span class=\"token class-name\">webpack<span class=\"token punctuation\">.</span>DllPlugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            name<span class=\"token operator\">:</span> <span class=\"token string\">'_dll_[name]'</span><span class=\"token punctuation\">,</span>\n            path<span class=\"token operator\">:</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span>__dirname<span class=\"token punctuation\">,</span> <span class=\"token string\">'./'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'[name].dll.manifest.json'</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<ol start=\"2\">\n<li>添加并执行dll命令\"./node_modules/.bin/webpack --mode production --config webpack.dll.config.js\"</li>\n<li>yarn run dll生成react.dll.manifest.json及打包react、lodash之后的模块js</li>\n<li>此时dll文件是带有hash的，为了将js注入到页面上,这里我们借助add-asset-html-webpack-plugin。</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">autoAddDllRes</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> AddAssetHtmlPlugin <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'add-asset-html-webpack-plugin'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">AddAssetHtmlPlugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span>   <span class=\"token comment\">// 往html中注入dll js</span>\n    publicPath<span class=\"token operator\">:</span> <span class=\"token string\">'./dll/'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 注入到html中的路径</span>\n    outputPath<span class=\"token operator\">:</span> <span class=\"token string\">'dll'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 最终输出的目录</span>\n    filepath<span class=\"token operator\">:</span> path<span class=\"token punctuation\">.</span><span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./dll/*.js'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    includeSourcemap<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    typeOfAsset<span class=\"token operator\">:</span> <span class=\"token string\">'js'</span> <span class=\"token comment\">// options js、css; default js</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<ol start=\"5\">\n<li>webpack.config.js中添加plugin</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">new</span> <span class=\"token class-name\">webpack<span class=\"token punctuation\">.</span>DllReferencePlugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    manifest<span class=\"token operator\">:</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./react.dll.manifest.json'</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n<span class=\"token function\">autoAddDllRes</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></code></pre></div>\n<p>当不使用.cache及dll缓存时，build一次的时间为6000ms左右;使用dll时，二次构建的时间可以提升到3000ms。当然这里我们用到uglifyjs的cache文件夹时，打包速度会达到1000ms的量级，使得dll的配置效果不是那么明显。</p>\n<h3 id=\"tree-shaking\" style=\"position:relative;\"><a href=\"#tree-shaking\" aria-label=\"tree shaking permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Tree Shaking</h3>\n<p>Tree Shaking是指webpack利用ES6 import静态编译的特点, 打包时去除无用代码的一种方法。</p>\n<ol>\n<li>@babel/preset-env的默认modules为auto，此时若在package.json指定没有sideEffects的话，webpack在production模式自动开启tree-shaking；</li>\n<li>我们这里手动试验一下这个特性，写一个sideCode文件用ES6语法导出一个函数一个无用变量。</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">  <span class=\"token comment\">// sideCode.js</span>\n  <span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">a</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> unused <span class=\"token operator\">=</span> <span class=\"token string\">'unused'</span><span class=\"token punctuation\">;</span></code></pre></div>\n<ol start=\"3\">\n<li>避免杂项干扰，我们设置webpack mode为'none', optimization作如下配置：</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// providedExports: true,</span>\nusedExports<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\nminimize<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\nminimizer<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token keyword\">new</span> <span class=\"token class-name\">UglifyJsPlugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        exclude<span class=\"token operator\">:</span> <span class=\"token regex\">/\\.min\\.js$/</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 已压缩文件不再处理</span>\n        cache<span class=\"token operator\">:</span> <span class=\"token string\">'.cache'</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 缓存文件夹</span>\n        parallel<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 多进程</span>\n        sourceMap<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n        extractComments<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n        uglifyOptions<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n            compress<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n                unused<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n            output<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n                beautify<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n                comments<span class=\"token operator\">:</span> <span class=\"token boolean\">false</span> <span class=\"token comment\">// 不输出注释</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">]</span></code></pre></div>\n<p>  其中usedExports依赖默认为true的providedExports, 我们开启usedExports后，会发现导出的文件中包含 <em>/* unused harmony export unused */</em>的标示，此时我们开启minimize为true，由于compress中设置了unused为true，便发现再次打包时 我们的unused变量已经被去除了。</p>\n<ol start=\"4\">\n<li>需要注意一点的是，因为这个功能依赖ES6 import优先执行的特性，所以当我们显式设置 <code class=\"language-text\">presets: [[&#39;@babel/preset-env&#39;, {modules: &#39;cjs&#39;}]</code>时，会发现我们的未使用变量又被打包进来了。所以必须告诉webpack不要转换模块。</li>\n</ol>\n<h2 id=\"总结\" style=\"position:relative;\"><a href=\"#%E6%80%BB%E7%BB%93\" aria-label=\"总结 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>总结</h2>\n<p>这篇主要介绍了配置webpack时经常涉及到的<strong>Code Split</strong>、<strong>Dynamic Import</strong>、<strong>Tree Shaking</strong>及<strong>DLL</strong>常用技巧，希望能够在日常工作中得以运用。</p>","fields":{"slug":"/【webpack配置】一、常用基础插件🎉/"},"tableOfContents":"<ul>\n<li><a href=\"//#%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9B%AE%E5%BD%95\">初始化目录</a></li>\n<li>\n<p><a href=\"//#webpack%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6\">webpack配置文件</a></p>\n<ul>\n<li><a href=\"//#split-chunks\">split Chunks</a></li>\n<li><a href=\"//#dynamic-import\">dynamic import</a></li>\n<li><a href=\"//#dll-config\">dll config</a></li>\n<li><a href=\"//#tree-shaking\">Tree Shaking</a></li>\n</ul>\n</li>\n<li><a href=\"//#%E6%80%BB%E7%BB%93\">总结</a></li>\n</ul>","frontmatter":{"id":"d4b8d9c3ddc0e95c88f753df86ba56c7","description":"随着业务代码规模化，开发者对工程化也该引起足够重视。\n业务不断，优化不止。本着对最佳实践的持续探索，让我们从头开始，打怪升级成一名webpack配置攻城狮✌️","title":"【webpack配置】一、常用基础插件🎉","slug":"/","date":"2019年08月08日","tags":["webpack","工程化"],"headerImage":"https://2img.net/h/i968.photobucket.com/albums/ae170/laughingjacky/Blog%20Assets%202019/webpack-how-it-works_zpsu9wcudnq.png"}},"previous":null,"next":null}]},"site":{"siteMetadata":{"title":"王晓博 - 银河系漫游指南","description":"如果这个博客好久不更新了,说明我更浑浑噩噩了"}}},"pageContext":{"id":"9cc10200-df39-568b-a59b-5a05e0a78723","index":3}},"staticQueryHashes":[]}