zoukankan      html  css  js  c++  java
  • webpack优化相关操作

    1、缩小文件搜索的范围

        • 优化loader配置    

      尽量精确使用 include 只命中需要的文件。
        module.exports = {
          module: {
            rules: [
              {
                // 如果项目源码中只有 js 文件就不要写成 /.jsx?$/,提升正则表达式性能
                test: /.js$/,
                // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
                use: ['babel-loader?cacheDirectory'],
                // 只对项目根目录下的 src 目录中的文件采用 babel-loader
                include: path.resolve(__dirname, 'src'),
              },
            ]
          },
        };


          

      • 优化 resolve.modules 配置

        如果能明确第三方模块是在本项目下,那么避免递归向上查询。
        module.exports = {
          resolve: {
            // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
            // 其中 __dirname 表示当前工作目录,也就是项目根目录
            modules: [path.resolve(__dirname, 'node_modules')]
          },
        };    

        • 优化 resolve.mainFields 配置

        如果能明确第三方入口文件 描述字段,尽可能设置的少,
         由于大多数第三方模块都采用 main 字段去描述入口文件的位置,可以这样配置 Webpack:
        
        module.exports = {
          resolve: {
            // 只采用 main 字段作为入口文件描述字段,以减少搜索步骤
            mainFields: ['main'],
          },
        }

        • 优化 resolve.alias 配置

        对于一些完整性较强的库采用直接 定义路径 配置。如 react 库,vue库等。
        module.exports = {
      resolve: {
        // 使用 alias 把导入 react 的语句换成直接使用单独完整的 react.min.js 文件,
        // 减少耗时的递归解析操作
        alias: {
          'react': path.resolve(__dirname, './node_modules/react/dist/react.min.js'),
        }
      },
    };

        • 优化 resolve.extensions 配置

        代码书写时,尽量带上文件后缀。该项列表尽可能短,且高频的放在最前面,不可能的情况不要写。
        module.exports = {
          resolve: {
            // 尽可能的减少后缀尝试的可能性
            extensions: ['js'],
          },
        };    

        • 优化 module.noParse配置

        对没有采用模块化的文件 直接进行忽略设置,如 jQuery 、ChartJS
        const path = require('path');
        
        module.exports = {
          module: {
            // 独完整的 `react.min.js` 文件就没有采用模块化,忽略对 `react.min.js` 文件的递归解析处理
            noParse: [/react.min.js$/],
          },
        };    

    2、使用DLLPlugin插件

    使用动态链接库:对于一些大量复用的基础模块,只编译一次,放置到 动态链接库里。常用于包含第三方模块,如 react、react-dom。
    涉及问题:
    打包成动态链接库;如何使用。
    涉及插件:
    • DllPlugin 插件:用于打包出一个个单独的动态链接库文件。
    • DllReferencePlugin 插件:用于在主要配置文件中去引入 DllPlugin 插件打包好的动态链接库文件

    构建:
    构建输出的以下这四个文件
    ├── polyfill.dll.js
    ├── polyfill.manifest.json
    ├── react.dll.js
    └── react.manifest.json
    和以下这一个文件
    ├── main.js
    是由两份不同的构建分别输出的。
    动态链接库文件相关的文件需要由一份独立的构建输出,用于给主构建使用。新建一个 Webpack 配置文件 webpack_dll.config.js 专门用于构建它们,文件内容如下:
    const path = require('path');
    const DllPlugin = require('webpack/lib/DllPlugin');
    module.exports = {
      // JS 执行入口文件
      entry: {
        // 把 React 相关模块的放到一个单独的动态链接库
        react: ['react', 'react-dom'],
        // 把项目需要所有的 polyfill 放到一个单独的动态链接库
        polyfill: ['core-js/fn/object/assign', 'core-js/fn/promise', 'whatwg-fetch'],
      },
      output: {
        // 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
        // 也就是 entry 中配置的 react 和 polyfill
        filename: '[name].dll.js',
        // 输出的文件都放到 dist 目录下
        path: path.resolve(__dirname, 'dist'),
        // 存放动态链接库的全局变量名称,例如对应 react 来说就是 _dll_react
        // 之所以在前面加上 _dll_ 是为了防止全局变量冲突
        library: '_dll_[name]',
      },
      plugins: [
        // 接入 DllPlugin
        new DllPlugin({
          // 动态链接库的全局变量名称,需要和 output.library 中保持一致
          // 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
          // 例如 react.manifest.json 中就有 "name": "_dll_react"
          name: '_dll_[name]',
          // 描述动态链接库的 manifest.json 文件输出时的文件名称
          path: path.join(__dirname, 'dist', '[name].manifest.json'),
        }),
      ],
    };
    使用动态链接库文件

    构建出的动态链接库文件用于给其它地方使用,在这里也就是给执行入口使用。

    用于输出 main.js 的主 Webpack 配置文件内容如下:

    const path = require('path');
    const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');

    module.exports = {
      entry: {
        // 定义入口 Chunk
        main: './main.js'
      },
      output: {
        // 输出文件的名称
        filename: '[name].js',
        // 输出文件都放到 dist 目录下
        path: path.resolve(__dirname, 'dist'),
      },
      module: {
        rules: [
          {
            // 项目源码使用了 ES6 和 JSX 语法,需要使用 babel-loader 转换
            test: /.js$/,
            use: ['babel-loader'],
            exclude: path.resolve(__dirname, 'node_modules'),
          },
        ]
      },
      plugins: [
        // 告诉 Webpack 使用了哪些动态链接库
        new DllReferencePlugin({
          // 描述 react 动态链接库的文件内容
          manifest: require('./dist/react.manifest.json'),
        }),
        new DllReferencePlugin({
          // 描述 polyfill 动态链接库的文件内容
          manifest: require('./dist/polyfill.manifest.json'),
        }),
      ],
      devtool: 'source-map'
    };

        注意:在 webpack_dll.config.js 文件中,DllPlugin 中的 name 参数必须和 output.library 中保持一致。 原因在于 DllPlugin 中的 name 参数会影响输出的 manifest.json 文件中 name 字段的值, 而在 webpack.config.js 文件中 DllReferencePlugin 会去 manifest.json 文件读取 name 字段的值, 把值的内容作为在从全局变量中获取动态链接库中内容时的全局变量名。

    执行构建

    在修改好以上两个 Webpack 配置文件后,需要重新执行构建。 重新执行构建时要注意的是需要先把动态链接库相关的文件编译出来,因为主 Webpack 配置文件中定义的 DllReferencePlugin 依赖这些文件。

    执行构建时流程如下:

        如果动态链接库相关的文件还没有编译出来,就需要先把它们编译出来。方法是执行 webpack --config webpack_dll.config.js 命令。
        在确保动态链接库存在时,才能正常的编译出入口执行文件。方法是执行 webpack 命令。这时你会发现构建速度有了非常大的提升。

    3、happyPack 插件

    使用多进程 进行文件转换操作,提高转换效率。
    场景:
    文件特别多,时长不能忍时,尝试。普通项目效果不明显。

    涉及插件:
    HappyPack。
    npm i -D happypack

    分解工作 和 管理工作由插件负责
    实例:
    const path = require('path');
    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    const HappyPack = require('happypack');
    module.exports = {
      module: {
        rules: [
          {
            test: /.js$/,
            // 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
            use: ['happypack/loader?id=babel'],
            // 排除 node_modules 目录下的文件,node_modules 目录下的文件都是采用的 ES5 语法,没必要再通过 Babel 去转换
            exclude: path.resolve(__dirname, 'node_modules'),
          },
          {
            // 把对 .css 文件的处理转交给 id 为 css 的 HappyPack 实例
            test: /.css$/,
            use: ExtractTextPlugin.extract({
              use: ['happypack/loader?id=css'],
            }),
          },
        ]
      },
      plugins: [
        new HappyPack({
          // 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
          id: 'babel',
          // 如何处理 .js 文件,用法和 Loader 配置中一样
          loaders: ['babel-loader?cacheDirectory'],
          // ... 其它配置项
        }),
        new HappyPack({
          id: 'css',
          // 如何处理 .css 文件,用法和 Loader 配置中一样
          loaders: ['css-loader'],
        }),
        new ExtractTextPlugin({
          filename: `[name].css`,
        }),
      ],
    };
    以上代码有两点重要的修改:
        • 在 Loader 配置中,所有文件的处理都交给了 happypack/loader 去处理,使用紧跟其后的 querystring ?id=babel 去告诉 happypack/loader 去选择哪个 HappyPack 实例去处理文件。
        • 在 Plugin 配置中,新增了两个 HappyPack 实例分别用于告诉 happypack/loader 去如何处理 .js 和 .css 文件。选项中的 id 属性的值和上面 querystring 中的 ?id=babel 相对应,选项中的 loaders 属性和 Loader 配置中一样。
    在实例化 HappyPack 插件的时候,除了可以传入 id 和 loaders 两个参数外,HappyPack 还支持如下参数:
        • threads 代表开启几个子进程去处理这一类型的文件,默认是3个,类型必须是整数。
        • verbose 是否允许 HappyPack 输出日志,默认是 true。
        • threadPool 代表共享进程池,即多个 HappyPack 实例都使用同一个共享进程池中的子进程去处理任务,以防止资源占用过多,相关代码如下:
    const HappyPack = require('happypack');
    // 构造出共享进程池,进程池中包含5个子进程
    const happyThreadPool = HappyPack.ThreadPool({ size: 5 });
    module.exports = {
      plugins: [
        new HappyPack({
          // 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
          id: 'babel',
          // 如何处理 .js 文件,用法和 Loader 配置中一样
          loaders: ['babel-loader?cacheDirectory'],
          // 使用共享进程池中的子进程去处理任务
          threadPool: happyThreadPool,
        }),
        new HappyPack({
          id: 'css',
          // 如何处理 .css 文件,用法和 Loader 配置中一样
          loaders: ['css-loader'],
          // 使用共享进程池中的子进程去处理任务
          threadPool: happyThreadPool,
        }),
        new ExtractTextPlugin({
          filename: `[name].css`,
        }),
      ],
    };

    4、使用 parallelUglifyPlugin

    多进程 进行文件混淆压缩。每个子进程还是通过内置的UglifyJS 去压缩代码。
    场景:
    普通可用,有提升。

    涉及插件:
    npm i -D webpack-parallel-uglify-plugin

    实例:
    const path = require('path');
    const DefinePlugin = require('webpack/lib/DefinePlugin');
    const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
    module.exports = {
      plugins: [
        // 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
        new ParallelUglifyPlugin({
          // 传递给 UglifyJS 的参数
          uglifyJS: {
            output: {
              // 最紧凑的输出
              beautify: false,
              // 删除所有的注释
              comments: false,
            },
            compress: {
              // 在UglifyJs删除没有用到的代码时不输出警告
              warnings: false,
              // 删除所有的 `console` 语句,可以兼容ie浏览器
              drop_console: true,
              // 内嵌定义了但是只用到一次的变量
              collapse_vars: true,
              // 提取出出现多次但是没有定义成变量去引用的静态值
              reduce_vars: true,
            }
          },
        }),
      ],
    };
    在通过 new ParallelUglifyPlugin() 实例化时,支持以下参数:
        • test:使用正则去匹配哪些文件需要被 ParallelUglifyPlugin 压缩,默认是 /.js$/,也就是默认压缩所有的 .js 文件。
        • include:使用正则去命中需要被 ParallelUglifyPlugin 压缩的文件。默认为 []。
        • exclude:使用正则去命中不需要被 ParallelUglifyPlugin 压缩的文件。默认为 []。
        • cacheDir:缓存压缩后的结果,下次遇到一样的输入时直接从缓存中获取压缩后的结果并返回。cacheDir 用于配置缓存存放的目录路径。默认不会缓存,想开启缓存请设置一个目录路径。
        • workerCount:开启几个子进程去并发的执行压缩。默认是当前运行电脑的 CPU 核数减去1。
        • sourceMap:是否输出 Source Map,这会导致压缩过程变慢。
        • uglifyJS:用于压缩 ES5 代码时的配置,Object 类型,直接透传给 UglifyJS 的参数。
        • uglifyES:用于压缩 ES6 代码时的配置,Object 类型,直接透传给 UglifyES 的参数

    5、区分环境

    process.env.NODE_ENV !== 'production' 中的 NODE_ENV 和 'production' 两个值是社区的约定,通常使用这条判断语句在区分开发环境和线上环境。

    6、压缩代码

    压缩js:
    最优配置如下(1版本可用)
    const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin');

    module.exports = {
      plugins: [
        // 压缩输出的 JS 代码
        new UglifyJSPlugin({
          compress: {
            // 在UglifyJs删除没有用到的代码时不输出警告
            warnings: false,
            // 删除所有的 `console` 语句,可以兼容ie浏览器
            drop_console: true,
            // 内嵌定义了但是只用到一次的变量
            collapse_vars: true,
            // 提取出出现多次但是没有定义成变量去引用的静态值
            reduce_vars: true,
          },
          output: {
            // 最紧凑的输出
            beautify: false,
            // 删除所有的注释
            comments: false,
          }
        }),
      ],
    };
    注意事项:
    uglifyjsplugin 插件版本不一致,可能配置项也不一样,注意区分。目前有1和2。vue-cli 目前依赖的是 1 版本。

    压缩ES6:
    npm i -D uglifyjs-webpack-plugin@beta

    场景:
    支持es6环境的系统。如最新版Chrome等。暂时用处不大。

    const UglifyESPlugin = require('uglifyjs-webpack-plugin')

    module.exports = {
      plugins: [
        new UglifyESPlugin({
          // 多嵌套了一层
          uglifyOptions: {
            compress: {
              // 在UglifyJs删除没有用到的代码时不输出警告
              warnings: false,
              // 删除所有的 `console` 语句,可以兼容ie浏览器
              drop_console: true,
              // 内嵌定义了但是只用到一次的变量
              collapse_vars: true,
              // 提取出出现多次但是没有定义成变量去引用的静态值
              reduce_vars: true,
            },
            output: {
              // 最紧凑的输出
              beautify: false,
              // 删除所有的注释
              comments: false,
            }
          }
        })
      ]
    }

    压缩css:
    css-loader 选项 minimize 支持压缩。可用性 待测试
    use: ['css-loader?minimize']

    7、Tree Shaking

    去除无用代码(没有用到的)。得是 基于es6模块化规范的,才会被摇除。
    举例:


    配置:
    1、关闭es6 模块转换功能,保留es6 语法。此时用不到 es6 转换器。
    {
      "presets": [
        [
          "env",
          {
            "modules": false
          }
        ]
      ]
    }
    2、使用uglifyPlugin 插件来压缩,或者 启动 Webpack 时带上 --optimize-minimize 参数

    8、提取公共代码

    使用场景:
    多个页面时,每个页面都是一个独立的单页应用。会有很多相同资源 被重复加载。
    如何提取:
    1、多页面使用的技术栈一致的,此时将 基础库和 基础样式提取 作为基础库文件:base.js。
    以react 举例,所有页面会依赖 react、react-dom等库。
    2、与业务相关的 通用js 可提取到 业务基础文件:common.js。

    场景:
    作为基础库文件,基本不会变动;业务基础文件 可能变动性稍微大一些,做到了 最优缓存。

    webpck实现
    所用插件:
    CommonsChunkPlugin    webpack4 里用他俩替代
        optimization.splitChunks and optimization.runtimeChunk)
        
        来自 <https://blog.csdn.net/VhWfR2u02Q/article/details/79969250>
        

    示例-common提取:
    const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
    new CommonsChunkPlugin({
      // 从哪些 Chunk 中提取
      chunks: ['a', 'b'],
      // 提取出的公共部分形成一个新的 Chunk,这个新 Chunk 的名称
      name: 'common'
    })

    示例-base提取:
        base.js
    // 所有页面都依赖的基础库
    import 'react';
    import 'react-dom';
    // 所有页面都使用的样式
    import './base.css';

        base配置
    module.exports = {
      entry: {
        base: './base.js'
      },
    };

        从common中提取base
    new CommonsChunkPlugin({
      // 从 common 和 base 两个现成的 Chunk 中提取公共的部分
      chunks: ['common', 'base'],
      // 把公共的部分放到 base 中
      name: 'base'
    })

    示例-引用:
    <script src="base.js"></script>
    <script src="common.js"></script>
    <script src="a.js"></script>

    其他情形:
    除了基础库 内容,一些常用内容提取到 common.js 里。用到了 插件选项
    minChunks:指定的代码块中出现的最小次数。
    假如 minChunks=2、chunks=['a','b','c','d'],任何一个文件只要在 ['a','b','c','d'] 中任意两个以上的 Chunk 中都出现过,这个文件就会被提取出来

    9、按需加载

    支持异步加载。

    10、prepack

    求值器,编译时 提前将结果就编译进代码里,而不是 运行时才求值。
    涉及插件:
    prepack-webpack-plugin    目前只能运行在 webpack 4.0之上

    11、scope hoisiting 作用域提升

    文件内容合并,压缩 优化。仅用于 es6 语法。
    涉及插件:
    webpack.optimize.ModuleConcatenationPlugin

    最优配置:
    module.exports = {
      resolve: {
        // 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
        mainFields: ['jsnext:main', 'browser', 'main']
      },
      plugins: [
        // 开启 Scope Hoisting
        new ModuleConcatenationPlugin(),
      ],
    };

    12、输出分析用以 特定优化

    使用命令:
    webpack --profile --json > stats.json
    会在项目下生成 stats.json文件,里面包含了所有的 输出信息。

    可视化工具:
    1、在线可视,非常全。    http://webpack.github.io/analyse/
    2、插件    webpack-bundle-analyzer;全局安装,使用:先生成 stats.json文件,然后在项目下使用命令webpack-bundle-analyzer stats.json

    13、优化总结

    侧重优化开发体验的配置文件 webpack.config.js:

    const path = require('path');
    const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
    const {AutoWebPlugin} = require('web-webpack-plugin');
    const HappyPack = require('happypack');
    // 自动寻找 pages 目录下的所有目录,把每一个目录看成一个单页应用
    const autoWebPlugin = new AutoWebPlugin('./src/pages', {
      // HTML 模版文件所在的文件路径
      template: './template.html',
      // 提取出所有页面公共的代码
      commonsChunk: {
        // 提取出公共代码 Chunk 的名称
        name: 'common',
      },
    });
    module.exports = {
      // AutoWebPlugin 会找为寻找到的所有单页应用,生成对应的入口配置,
      // autoWebPlugin.entry 方法可以获取到生成入口配置
      entry: autoWebPlugin.entry({
        // 这里可以加入你额外需要的 Chunk 入口
        base: './src/base.js',
      }),
      output: {
        filename: '[name].js',
      },
      resolve: {
        // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
        // 其中 __dirname 表示当前工作目录,也就是项目根目录
        modules: [path.resolve(__dirname, 'node_modules')],
        // 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件,使用 Tree Shaking 优化
        // 只采用 main 字段作为入口文件描述字段,以减少搜索步骤
        mainFields: ['jsnext:main', 'main'],
      },
      module: {
        rules: [
          {
            // 如果项目源码中只有 js 文件就不要写成 /.jsx?$/,提升正则表达式性能
            test: /.js$/,
            // 使用 HappyPack 加速构建
            use: ['happypack/loader?id=babel'],
            // 只对项目根目录下的 src 目录中的文件采用 babel-loader
            include: path.resolve(__dirname, 'src'),
          },
          {
            test: /.js$/,
            use: ['happypack/loader?id=ui-component'],
            include: path.resolve(__dirname, 'src'),
          },
          {
            // 增加对 CSS 文件的支持
            test: /.css$/,
            use: ['happypack/loader?id=css'],
          },
        ]
      },
      plugins: [
        autoWebPlugin,
        // 使用 HappyPack 加速构建
        new HappyPack({
          id: 'babel',
          // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
          loaders: ['babel-loader?cacheDirectory'],
        }),
        new HappyPack({
          // UI 组件加载拆分
          id: 'ui-component',
          loaders: [{
            loader: 'ui-component-loader',
            options: {
              lib: 'antd',
              style: 'style/index.css',
              camel2: '-'
            }
          }],
        }),
        new HappyPack({
          id: 'css',
          // 如何处理 .css 文件,用法和 Loader 配置中一样
          loaders: ['style-loader', 'css-loader'],
        }),
        // 4-11提取公共代码
        new CommonsChunkPlugin({
          // 从 common 和 base 两个现成的 Chunk 中提取公共的部分
          chunks: ['common', 'base'],
          // 把公共的部分放到 base 中
          name: 'base'
        }),
      ],
      watchOptions: {
        // 4-5使用自动刷新:不监听的 node_modules 目录下的文件
        ignored: /node_modules/,
      }
    };


    侧重优化输出质量的配置文件 webpack-dist.config.js:

    const path = require('path');
    const DefinePlugin = require('webpack/lib/DefinePlugin');
    const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
    const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    const {AutoWebPlugin} = require('web-webpack-plugin');
    const HappyPack = require('happypack');
    const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
    // 自动寻找 pages 目录下的所有目录,把每一个目录看成一个单页应用
    const autoWebPlugin = new AutoWebPlugin('./src/pages', {
      // HTML 模版文件所在的文件路径
      template: './template.html',
      // 提取出所有页面公共的代码
      commonsChunk: {
        // 提取出公共代码 Chunk 的名称
        name: 'common',
      },
      // 指定存放 CSS 文件的 CDN 目录 URL
      stylePublicPath: '//css.cdn.com/id/',
    });
    module.exports = {
      // AutoWebPlugin 会找为寻找到的所有单页应用,生成对应的入口配置,
      // autoWebPlugin.entry 方法可以获取到生成入口配置
      entry: autoWebPlugin.entry({
        // 这里可以加入你额外需要的 Chunk 入口
        base: './src/base.js',
      }),
      output: {
        // 给输出的文件名称加上 Hash 值
        filename: '[name]_[chunkhash:8].js',
        path: path.resolve(__dirname, './dist'),
        // 指定存放 JavaScript 文件的 CDN 目录 URL
        publicPath: '//js.cdn.com/id/',
      },
      resolve: {
        // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
        // 其中 __dirname 表示当前工作目录,也就是项目根目录
        modules: [path.resolve(__dirname, 'node_modules')],
        // 只采用 main 字段作为入口文件描述字段,以减少搜索步骤
        mainFields: ['jsnext:main', 'main'],
      },
      module: {
        rules: [
          {
            // 如果项目源码中只有 js 文件就不要写成 /.jsx?$/,提升正则表达式性能
            test: /.js$/,
            // 使用 HappyPack 加速构建
            use: ['happypack/loader?id=babel'],
            // 只对项目根目录下的 src 目录中的文件采用 babel-loader
            include: path.resolve(__dirname, 'src'),
          },
          {
            test: /.js$/,
            use: ['happypack/loader?id=ui-component'],
            include: path.resolve(__dirname, 'src'),
          },
          {
            // 增加对 CSS 文件的支持
            test: /.css$/,
            // 提取出 Chunk 中的 CSS 代码到单独的文件中
            use: ExtractTextPlugin.extract({
              use: ['happypack/loader?id=css'],
              // 指定存放 CSS 中导入的资源(例如图片)的 CDN 目录 URL
              publicPath: '//img.cdn.com/id/'
            }),
          },
        ]
      },
      plugins: [
        autoWebPlugin,
        // 4-14开启ScopeHoisting
        new ModuleConcatenationPlugin(),
        // 4-3使用HappyPack
        new HappyPack({
          // 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
          id: 'babel',
          // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
          loaders: ['babel-loader?cacheDirectory'],
        }),
        new HappyPack({
          // UI 组件加载拆分
          id: 'ui-component',
          loaders: [{
            loader: 'ui-component-loader',
            options: {
              lib: 'antd',
              style: 'style/index.css',
              camel2: '-'
            }
          }],
        }),
        new HappyPack({
          id: 'css',
          // 如何处理 .css 文件,用法和 Loader 配置中一样
          // 通过 minimize 选项压缩 CSS 代码
          loaders: ['css-loader?minimize'],
        }),
        new ExtractTextPlugin({
          // 给输出的 CSS 文件名称加上 Hash 值
          filename: `[name]_[contenthash:8].css`,
        }),
        // 4-11提取公共代码
        new CommonsChunkPlugin({
          // 从 common 和 base 两个现成的 Chunk 中提取公共的部分
          chunks: ['common', 'base'],
          // 把公共的部分放到 base 中
          name: 'base'
        }),
        new DefinePlugin({
          // 定义 NODE_ENV 环境变量为 production 去除 react 代码中的开发时才需要的部分
          'process.env': {
            NODE_ENV: JSON.stringify('production')
          }
        }),
        // 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
        new ParallelUglifyPlugin({
          // 传递给 UglifyJS 的参数
          uglifyJS: {
            output: {
              // 最紧凑的输出
              beautify: false,
              // 删除所有的注释
              comments: false,
            },
            compress: {
              // 在UglifyJs删除没有用到的代码时不输出警告
              warnings: false,
              // 删除所有的 `console` 语句,可以兼容ie浏览器
              drop_console: true,
              // 内嵌定义了但是只用到一次的变量
              collapse_vars: true,
              // 提取出出现多次但是没有定义成变量去引用的静态值
              reduce_vars: true,
            }
          },
        }),
      ]
    };
  • 相关阅读:
    数据结构之单链表及其函数算法
    数据结构之KMP算法next数组
    FastDFS的简单使用
    富文本编辑器kindeditor的使用
    SpringSecurity的简单入门
    Dubbo+zookeeper实现单表的增删改查
    windows批量删除当前目录以及子目录的所有空文件夹
    Echarts的简单入门
    基于JAX-RS规范的webService入门
    RESTFull开发风格
  • 原文地址:https://www.cnblogs.com/fan-zha/p/10517252.html
Copyright © 2011-2022 走看看