Webpack性能优化

2020-01-27  本文已影响0人  指尖跳动

一、跟上技术迭代(Webpack、Node、Npm、Yarn等)

webpack较新的版本相对旧版本会有些优化,会提升打包速度。webpack是建立在node的运行环境之上的,新版本的node运行效率也会有所提升。Npm、Yarn等包管理工具新的版本在包依赖和包的引入也会间接提升打包效率。

二、在尽可能少的模块上应用Loader

例如,处理js的模块,添加exclude: /node_modules/的配置可以减少对第三方的解析,一般第三方模块已经被打包编译过,没有必要再进行编译。

三、Plugin尽可能精简并确保可靠

例如,
1、线上代码需要对代码进行压缩,开发环境没有必要对代码进行压缩,所以开发环境没有必要使用对代码进行压缩的插件。
2、尽可能使用官方推荐的插件,官方推荐的插件是经过性能测试的,性能比较快,使用第三方公司或者个人编写的插件,性能得不到保障。

四、resolve参数合理配置

例如,
1、webpack做了如下配置:

resolve: {
    extensions: ['.css','.jpg','.js', '.jsx', '.vue', '.json']
  }

resolve.extensions配置可以使在引入文件时省去文件后缀,在引入的时候可以这样写:

import File from '../path/to/file';

webpack会依次查找'../path/to/file.css'、'../path/to/file.jpg'、 '../path/to/file.js'、 '../path/to/file.jsx'、 '../path/to/file.vue'、 '../path/to/file.json',会消耗性能,所以一般extensions中只配置js、vue这种逻辑的文件。

2、

resolve: {
    mainFiles: ['index']
  }

resolve.mainFiles可以在引入时省略文件名,配置过多同样会影响性能。

五、使用DllPlugin提高打包速度

我们在开发过程中会用到很多第三方模块,这些模版我们更新的不是很频繁,但是如果我们在开发过程中每次更新代码都对他们也进行打包就会浪费很对性能。可以使用DllPlugin+DllReferencePlugin解决这个问题。

使用详解:
1、在项目中新增webpack配置文件。

const path = require('path');
const webpack = require('webpack')
module.exports = {
    mode: 'production',
    entry: {
        // vendors: ['react','react-dom','lodash']
        vendors: ['lodash'],
        react: ['react','react-dom'],
        jquery: ['jquery']
    },
    output: {
        filename: "[name].dll.js",
        path: path.resolve(__dirname, '../dll'),
        library: '[name]' // 把打包的文件通过变量暴露出来
    },
    plugins: [
        new webpack.DllPlugin({
            name: '[name]',
            path: path.resolve(__dirname, '../dll/[name].manifest.json'),
        })
    ]
}

webpack执行这个文件会生成这个文件夹


manifest.json文件是用来让 DLLReferencePlugin 映射到相关的依赖上去的。
主webpack配置文件如下:
const path = require('path');
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 fs = require('fs')

const plugins = [
    new HtmlWebpackPlugin({
        template: 'src/index.html'
    }),
    new CleanWebpackPlugin(['dist'], {
        root: path.resolve(__dirname, '../')
    })
]

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)
            })
        )
    }
})

module.exports = {
    entry: {
        main: './src/index.js',
    },
    resolve: {
        extensions: ['.js', '.jsx'],
        alias: {
            child: path.resolve(__dirname, '../src/a/b/c/child')
        }
    },
    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'
            }
        }]
    },
    plugins,
    /*plugins: [

        new HtmlWebpackPlugin({
            template: 'src/index.html'
        }),
        new CleanWebpackPlugin(['dist'], {
            root: path.resolve(__dirname, '../')
        }),

        new AddAssetHtmlWebpackPlugin({
            filepath: path.resolve(__dirname, '../dll/vendors.dll.js')
        }),
        new AddAssetHtmlWebpackPlugin({
            filepath: path.resolve(__dirname, '../dll/react.dll.js')
        }),
        new webpack.DllReferencePlugin({ // dll引用的插件,当打包过程发现第三方模块的时候就去vendors.manifest.json中去找映射关系
            manifest: path.resolve(__dirname, '../dll/vendors.manifest.json')
        }),
        new webpack.DllReferencePlugin({ // dll引用的插件,当打包过程发现第三方模块的时候就去vendors.manifest.json中去找映射关系
            manifest: path.resolve(__dirname, '../dll/react.manifest.json')
        }),
    ],*/
    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')
    }
}

AddAssetHtmlWebpackPlugin插件把打包生成的相应文件引入到html文件中。可以通过fs动态读取dell文件夹中的文件,动态添加到plugin中。

DllReferencePlugin这个插件把只有 dll 的包引用到需要的预编译的依赖。
当项目中引入第三方库较多的时候使用该方法对打包性能的提升是很大的。

六、控制包文件大小

1、Tree Sharking

Tree Sharking可以忽略掉没有用到的代码,Tree Sharking只支持ES Module模块的引用,因为ES Module模块引用是静态的,commonJs是动态的,Tree Sharking只支持静态引用。mode: production是自动带Tree Sharking的,mode: development模式需要手动添加如下配置。

optimization: {
    usedExports: true
  }

同时需要在package.json中添加

"sideEffects":  []

如果不配置sideEffects,像

import './style/style.css'

这种引用,Tree Sharking会认为这个import没有引用任何模块,就不会对它进行打包。所以需要把直接引用的模块添加到sideEffects对应的数组中。

  "sideEffects": [
    "*.css"
  ]

使用Tree Sharking可以一定程度上提高打包效率。

七、thread-loader、parallel-webpack、happypack多进程打包。

八、合理使用sourceMap

九、结合stats分析打包结果

十、开发环境内存编译

上一篇下一篇

猜你喜欢

热点阅读