Webpack实战配置案例(二)

EsLint 在 Webpack 中的配置

//安装eslint工具,规范项目中的代码
npm i eslint -D
npm i babel-eslint -D
npm i eslint-loader -D

//快速生成eslint配置
npx eslint --init

在 .eslintrc.js 中:

module.exports = {
    "extends": "airbnb",
  "parser": "babel-eslint",
  "rules": {
    "react/prefer-stateless-function": 0,
    "react/jsx-filename-extension": 0
  },
  globals: {
    document: false
  }
};

详细请看官方文档:eslint

在 vscode 编辑器里安装 eslint 插件,自动检测语法错误。(推荐使用)

在 webpack.config.js 中:

devServer: {
+        overlay: true,//在浏览器弹出提示有错误
    },


rules: [{ 
            test: /\.js$/, 
            exclude: /node_modules/, 
    +        use: ['babel-loader', 'eslint-loader'] //先检查代码写的是否规范,在转换成es5
        },
        ...],

在真实项目中,也可以不在webpack 中配置eslint,在提交git仓库时,git 钩子 eslint src 。但是没有图形交互式的错误提示。

详细请看官方文档:eslint-loader


提升 webpack 打包速度的方法

  1. 跟上技术的迭代(Node,Npm,Yarn)
  2. 在尽可能少的模块上应用 Loader
  3. Plugin 尽可能精简并确保可靠

  4. resolve 参数合理配置, 引入资源文件写后缀,像 图片文件(.jpg, .png, .svg),逻辑代码配置在extensions中:extensions: ['.js', '.jsx']

  5. 使用 DLLPlugin 提高打包速度   详细请看官方文档:dll-plugin

  6. 实现第三方模块只打包一次

安装:

npm i add-asset-html-webpack-plugin --save

在 build 文件夹里创建 webpack.dll.js 文件:把第三方模块单独进行打包,生成一个vendors.dll.js 文件,所有的第三方模块都在这个文件里。

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

module.exports = {
    mode: 'production',
    entry: {
        vendors: ['lodash'],
        react: ['react', 'react-dom'],
        jquery: ['jquery']
    },
    output: {
        filename: '[name].dll.js',
        path: path.resolve(__dirname, '../dll'),
        library: '[name]'//打包生成的库名,通过全局变量的形式暴露到全局
    },
    plugins: [
        new webpack.DllPlugin({//对暴露到全局的代码进行分析,生成vendors.manifest.json 的映射文件,
            name: '[name]',
            path: path.resolve(__dirname, '../dll/[name].manifest.json'),
        })
    ]
}

在 webpack.common.js 中:

const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
files.forEach(file => {
    if(/.*\.dll.js/.test(file)) {
        plugins.push(new AddAssetHtmlWebpackPlugin({//将打包好的dll文件挂载到html中
            filepath: path.resolve(__dirname, '../dll', file)
        }))
    }
    if(/.*\.manifest.json/.test(file)) {
        plugins.push(new webpack.DllReferencePlugin({//分析第三方模块是否已经在dll文件里,如果里面有就不用再node_modules在分析打包了
            manifest: path.resolve(__dirname, '../dll', file)
        }))
    }
})

总结:

如果不使用使用 DLLPlugin 插件,当引入第三方模块时,每一次打包都要进行分析,是消耗打包的性能的。使用 DLLPlugin 提高打包速度,在第一次打包时,把第三方模块单独打包生成一个文件 vendors.dll.js ,之后在打包时就可以直接从 vendors.dll.js 中引入之前打包好的第三方模块,速度就会变快。

要想实现,就得做一些配置:

先配置 webpack.dll.js 文件,在配置 webpack.common.js 文件

==============================================================

.dll 为后缀的文件称为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据

  • 把基础模块独立出来打包到单独的动态连接库里
  • 当需要导入的模块在动态连接库里的时候,模块不能再次被打包,而是去动态连接库里获取 dll-plugin

定义Dll

  • DllPlugin插件: 用于打包出一个个动态连接库
  • DllReferencePlugin: 在配置文件中引入DllPlugin插件打包好的动态连接库

在 webpack.dll.js 中:

module.exports = {
    entry: {
        react: ['react'] //react模块打包到一个动态连接库
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].dll.js', //输出动态连接库的文件名称
        library: '_dll_[name]' //全局变量名称
    },
    plugins: [
        new webpack.DllPlugin({
            name: '_dll_[name]', //和output.library中一致,值就是输出的manifest.json中的 name值
            path: path.join(__dirname, 'dist', '[name].manifest.json')
        })
    ]
}
webpack --config webpack.dll.config.js --mode production

使用动态链接库文件

在 webpack.common.js 中:

plugins: [
+        new webpack.DllReferencePlugin({
+            manifest: require(path.join(__dirname, 'dist', 'react.manifest.json')),
+        })
    ],



webpack --config webpack.config.js --mode development

==============================================================

6.控制包文件大小

配置 Tree shaking,把用不到的代码去除掉。配置 SplitChunksPlugin。

7.thread-loader,parallel-webpack,happypack 多进程打包

HappyPack就能让Webpack把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。 happypack

安装:npm i happypack@next -D

配置:

module: {
        rules: [{
            test: /\.js$/,
            //把对.js文件的处理转交给id为babel的HappyPack实例
 +          use: 'happypack/loader?id=babel',
            include: path.resolve(__dirname, 'src'),
            exclude: /node_modules/
        }, {
            //把对.css文件的处理转交给id为css的HappyPack实例
            test: /\.css$/,
+           use: 'happypack/loader?id=css',
            include: path.resolve(__dirname, 'src')
        }],
        noParse: [/react\.min\.js/]
    },
plugins: [
        //用唯一的标识符id来代表当前的HappyPack是用来处理一类特定文件
        new HappyPack({
            id: 'babel',
            //如何处理.js文件,和rules里的配置相同
            loaders: [{
                loader: 'babel-loader',
                query: {
                    presets: [
                        "env", "react"
                    ]
                }
            }]
        }),
        new HappyPack({
            id: 'css',
            loaders: ['style-loader', 'css-loader'],
            threads: 4, //代表开启几个子进程去处理这一类型的文件
            verbose: true //是否允许输出日子
        })
    ],

ParallelUglifyPlugin可以把对JS文件的串行压缩变为开启多个子进程并行执行

安装:npm i -D webpack-parallel-uglify-plugin

配置:

new ParallelUglifyPlugin({
            workerCount: 3, //开启几个子进程去并发的执行压缩。默认是当前运行电脑的 CPU 核数减去1
            uglifyJS: {
                output: {
                    beautify: false, //不需要格式化
                    comments: false, //不保留注释
                },
                compress: {
                    warnings: false, // 在UglifyJs删除没有用到的代码时不输出警告
                    drop_console: true, // 删除所有的 `console` 语句,可以兼容ie浏览器
                    collapse_vars: true, // 内嵌定义了但是只用到一次的变量
                    reduce_vars: true, // 提取出出现多次但是没有定义成变量去引用的静态值
                }
            },
        })

8.合理使用 sourceMap

9.结合 stats 分析打包结果

10. 开发环境内存编译

11.开发环境无用插件剔除


多页面打包配置

配置多个 entry 里的 html 页面,用HtmlWebpackPlugin 插件,将打包好的j多个js分别插入到对应的html页面中。

在 webpack.common.js 中:

const path = require('path');
const fs = require('fs');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const webpack = require('webpack');


const makePlugins = (configs) => {
    const plugins = [
        new CleanWebpackPlugin(['dist'], {
            root: path.resolve(__dirname, '../')
        })
    ];
    Object.keys(configs.entry).forEach(item => {
        plugins.push(
+            new HtmlWebpackPlugin({
                template: 'src/index.html',
                filename: `${item}.html`,
                chunks: ['runtime', 'vendors', item]
            })
        )
    });
    const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
    files.forEach(file => {
        if(/.*\.dll.js/.test(file)) {
            plugins.push(new AddAssetHtmlWebpackPlugin({
                filepath: path.resolve(__dirname, '../dll', file)
            }))
        }
        if(/.*\.manifest.json/.test(file)) {
            plugins.push(new webpack.DllReferencePlugin({
                manifest: path.resolve(__dirname, '../dll', file)
            }))
        }
    });
    return plugins;
}

const configs = {
+    entry: {
        index: './src/index.js',
        list: './src/list.js',
        detail: './src/detail.js',
    },
    resolve: {
        extensions: ['.js', '.jsx'],
    },
    module: {
        rules: [{ 
            test: /\.jsx?$/, 
            include: path.resolve(__dirname, '../src'),
            use: [{
                loader: 'babel-loader'
            }]
        }, {
            test: /\.(jpg|png|gif)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name]_[hash].[ext]',
                    outputPath: 'images/',
                    limit: 10240
                }
            } 
        }, {
            test: /\.(eot|ttf|svg)$/,
            use: {
                loader: 'file-loader'
            } 
        }]
    },
    optimization: {
        runtimeChunk: {
            name: 'runtime'
        },
        usedExports: true,
        splitChunks: {
      chunks: 'all',
      cacheGroups: {
          vendors: {
              test: /[\\/]node_modules[\\/]/,
              priority: -10,
              name: 'vendors',
          }
      }
    }
    },
    performance: false,
    output: {
        path: path.resolve(__dirname, '../dist')
    }
}

configs.plugins = makePlugins(configs);

module.exports = configs

 

你可能感兴趣的:(WebPack)