1、如果可以的话,尽量使用高版本的 Webpack 和 Node.js;

2、多进程/多实例构建:

HappyPack(多进程压缩优化打包速度的,不过现在已经不维护了)、thread-loader

3、压缩代码

        ① 图片压缩

一般使用 loader 进行压缩:例如配置 image-webpack-loader

        ② CSS压缩

通过 mini-css-extract-plugin 分离样式文件,将 CSS 提取为独立文件,支持按需加载;还通过 css-loader 的 minimize 选项开启 cssnano 压缩 CSS。

         ③ 开启多进程执行代码压缩,提升构建速度

webpack-paralle-uglify-plugin

terser-webpack-plugin 开启 parallel 参数,压缩 ES6

4、 Tree shaking 摇树

打包过程中检测工程中没有引用过的模块并进行标记,在资源压缩时将它们从最终的 bundle中去掉(只能对 ES6 Modlue 生效) ,所以开发中尽可能使用 ES6 Module 的模块,提高 tree shaking 效率禁用 babel-loader 的模块依赖解析,否则 Webpack 接收到的就都是转换过的 CommonJS 形式的模块,无法进行 tree-shaking 使用 PurifyCSS(不在维护) 或者 uncss 去除无用 CSS 代码

purgecss-webpack-plugin 和 mini-css-extract-plugin配合使用(建议)

5、缩小打包作用域

通过配置 exclude / include (缩小 loader 解析范围)配置resolve.modules 指明第三方模块的绝对路径 (减少不必要的查找)配置 IgnorePlugin (确定完全的排除模块)合理配置别名alias(减少查找过程)resolve.mainFields 只采用 main 字段作为入口文件描述字段 (减少搜索步骤,需要考虑到所有运行时依赖的第三方模块的入口文件描述字段)resolve.extensions 尽可能减少后缀尝试的可能性noParse 对完全不需要解析的库进行忽略 (不去解析但仍会打包到 bundle 中,注意被忽略掉的文件里不应该包含 import、require、define 等模块化语句)

6、充分利用缓存提升二次构建速度

启用 babel-loader 的 cacheDirectory 开启缓存terser-webpack-plugin 开启缓存使用 cache-loader 或者 hard-source-webpack-plugin

7、提取页面公共资源

基础包分离:

使用 html-webpack-externals-plugin,将基础包通过 CDN 引入,不打入 bundle 中;

使用 SplitChunksPlugin 进行合理分包,提供代码的加载性能。该插件webpack已经默认安装和集成,只需要配置。

使用 DllPlugin 进行分包,使用 DllReferencePlugin(索引链接) 对 manifest.json 引用,让一些基本不会改动的代码先打包成静态资源,避免反复编译浪费时间。

通常来说,我们的代码都可以至少简单区分成业务代码和第三方库。如果不做处理,每次构建时都需要把所有的代码重新构建一次,耗费大量的时间。然后大部分情况下,很多第三方库的代码并不会发生变更(除非是版本升级),这时就可以用到dll;

把复用性较高的第三方模块打包到动态链接库中,在不升级这些库的情况下,动态库不需要重新打包,每次构建只重新打包业务代码。

使用 dll 时,构建过程分成 dll 构建过程和主构建过程,所以需要两个构建配置文件,例如叫做webpack.config.js和webpack.dll.config.js。

步骤:

使用DLLPlugin进行分包,对第三方包打包,完成后打包结果保存在项目中,后面就不需要再构建第三方包了。每次构建业务项目时候,使用 DllReferencePlugin 实现对构建好的第三方包dll的解析和处理。

HashedModuleIdsPlugin 可以解决模块数字id问题 Scope hoisting

「作用域提升」将每个模块都提升到引入者顶部,这样模块不会因为依赖链路较深而导致调用栈变深,它们都在同一层。

构建后的代码会存在大量闭包,造成体积增大,运行代码时创建的函数作用域变多,内存开销变大。Scope hoisting 将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突必须是ES6的语法,因为有很多第三方库仍采用 CommonJS 语法,为了充分发挥 Scope hoisting 的作用,需要配置 mainFields 对第三方模块优先采用 jsnext:main 中指向的ES6模块化语法

动态Polyfill

建议采用 polyfill-service 只给用户返回需要的polyfill,社区维护。 (部分国内奇葩浏览器UA可能无法识别,但可以降级返回所需全部polyfill)

8、关闭 sourceMap

关闭生成 map 文件 可以达到缩小打包体积。这个生产环境一定要关闭,不然打包的产物会很大。

9、webpack 长缓存优化

js文件使用 chunkhash,不使用 hash; css文件使用 contenthash,不使用chunkhash,不受js变化影响;

提取vendor,公共库不受业务模块变化影响; 内联webpack runtime 到页面,chunkld 变化不影响 vendor; 保证module ld稳定,不使用数字作为模块 id,改用文件内容的 hash值,使用HashedModuleldsPlugin,模块的新增或删除,会导致其后面的所有模块 id 重新排序,为避免这个问题; 保证chunkhash稳定,使用webpack-chunk-hash,替代 webpack自己的 hash算法,webpack 自己的 hash 算法,对于同一个文件,在不同开发环境下,会计算出不用的 hash 值,不能满足跨平台需求。

8、打包优化(主要是 webpack 优化)

拆包 extemals dllPlugin;

提取公共包 commonChunkPlugin 或 splitChunks; 缩小范围 各种 loader 配置 include和 exclude,noParse 跳过文件; 开启缓存 各种 loader 开启 cache;多线程加速 happypack或 thead-loader; Scope Hoisting ES6 模块分析,将多个模块合并到一个函数里,减少内存占用,减小体积,提示运行速度

 ① webpack优化:resolve.alias配置(vite同理)

resolve.alias 配置通过别名来将原导入路径映射成一个新的导入路径。 可以起到两个作用:【起别名;减少查找过程】例如:

resolve: {

alias: {

'vue$': 'vue/dist/vue.esm.js',

'@': resolve('src'),

}

},

② webpack优化:resolve.extensions配置(vite同理)

resolve.extensions 代表后缀尝试列表,它也会影响构建的性能,默认是:extensions: ['.js', '.json']

例如遇到 require('./data') 这样的导入语句时,Webpack会先去寻找 ./data.js 文件,如果该文件不存在就去寻找 ./data.json 文件,如果还是找不到就报错。  

【所以后缀尝试列表要尽可能的小,不要把项目中不可能存在的情况写到后缀尝试列表中,频率出现最高的文件后缀要优先放在最前面,以做到尽快的退出寻找过程。】

在源码中写导入语句时,要尽可能的带上后缀,从而可以避免寻找过程。例如在你确定的情况下把require('./data')写成require('./data.json')。

resolve: {

extensions: ['.js', '.vue', '.json'],

}

③ webpack优化:缩小 loader 范围

loader 是很消耗性能的一个点,我们在配置 loader 的时候,可以使用 include 和 exclude 来缩小loader 执行范围,从而优化性能。 例如:

{

test: /\.svg$/,

loader: 'svg-sprite-loader',

include: [resolve('src/icons')]

},

④ split chunks 代码分包

在没配置任何东西的情况下,webpack 4 就智能的帮你做了代码分包。入口文件依赖的文件都被打包进了main.js,那些大于 30kb 的第三方包,如:echarts、xlsx、dropzone等都被单独打包成了一个个独立 bundle。 其它被我们设置了异步加载的页面或者组件变成了一个个chunk,也就是被打包成独立的bundle。 它内置的代码分割策略是这样的:

新的 chunk 是否被共享或者是来自 node_modules 的模块; 新的 chunk 体积在压缩之前是否大于 30kb; 按需加载 chunk 的并发请求数量小于等于 5 个; 页面初始加载时的并发请求数量小于等于 3 个;

大家可以根据自己的项目环境来更改配置。webpack配置代码如下:

splitChunks({

cacheGroups: {

vendors: {

name: `chunk-vendors`,

test: /[\\/]node_modules[\\/]/,

priority: -10,

chunks: 'initial',

},

dll: {

name: `chunk-dll`,

test: /[\\/]bizcharts|[\\/]\@antv[\\/]data-set/,

priority: 15,

chunks: 'all',

reuseExistingChunk: true

},

common: {

name: `chunk-common`,

minChunks: 2,

priority: -20,

chunks: 'all',

reuseExistingChunk: true

},

}

})

没有使用webpack4.x版本的项目,可以通过按需加载的形式进行分包:webpack如何使用按需加载

vite配置代码如下:

build: {

rollupOptions: {

output: {

chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称

entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称

assetFileNames: '[ext]/[name]-[hash].[ext]' // 资源文件像 字体,图片等

}

}

}

⑤ tree shaking

tree shaking(摇树)。望文生义,它是用来清除我们项目中的一些无用代码,它依赖于ES中的模块语法得以实现。 比如日常使用 lodash 的时候:

import _ from 'lodash'

如果如上引用 lodash 库,在构建包的时候是会把整个 lodash 包打入到我们的 bundle 包中的。

import _isEmpty from 'lodash/isEmpty';

如果如上引用 lodash 库,在构建包的时候只会把 isEmpty 这个方法抽离出来再打入到我们的bundle包中。

tree shaking可以大大减少包体积,是性能优化中的重要一环。 在 vite 和 webpack4.x 中都已经默认开启 tree-shaking。

⑥ vite关闭一些打包配置项

webpack也有类似的配置,自行查阅

build: {

terserOptions: {

compress: {

//生产环境时移除console

drop_console: true,

drop_debugger: true,

},

},

//关闭文件计算

reportCompressedSize: false,

//关闭生成map文件 可以达到缩小打包体积

sourcemap: false, // 这个生产环境一定要关闭,不然打包的产物会很大

}

通过webpack优化前端的手段有:

① JS代码压缩        ② CSS代码压缩        ③ HTML文件代码压缩

④ 文件大小压缩     ⑤ 图片压缩               ⑥ Tree Shaking

⑦ 代码分离            ⑧ 内联 chunk

1、JS代码压缩

terser是一个JavaScript的解释、绞肉机、压缩机的工具集,可以帮助我们压缩、丑化我们的代码,让bundle更小。

在production模式下,webpack 默认就是使用 TerserPlugin 来处理我们的代码的。如果想要自定义配置它,配置方法如下:

const TerserPlugin = require('terser-webpack-plugin')

module.exports = {

...

optimization: {

minimize: true,

minimizer: [

new TerserPlugin({

parallel: true // 电脑cpu核数-1

})

]

}

}

属性介绍如下:

extractComments:默认值为true,表示会将注释抽取到一个单独的文件中。开发阶段可设置为 false,不保留注释parallel:使用多进程并发运行提高构建的速度,默认值是true。并发运行的默认数量: os.cpus().length - 1terserOptions:设置我们的terser相关的配置:compress:设置压缩相关的选项,mangle:设置丑化相关的选项,可以直接设置为truemangle:设置丑化相关的选项,可以直接设置为truetoplevel:底层变量是否进行转换keep_classnames:保留类的名称keep_fnames:保留函数的名称

2、CSS代码压缩

CSS压缩通常是去除无用的空格等,因为很难去修改选择器、属性的名称、值等。

CSS的压缩我们可以使用另外一个插件:CssMinimizerPlugin

配置方法如下:

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {

// ...

optimization: {

minimize: true,

minimizer: [

new CssMinimizerPlugin({

parallel: true

})

]

}

}

3、HTML文件代码压缩

使用 HtmlWebpackPlugin插件来生成HTML的模板时候,通过配置属性minify进行html优化。

module.exports = {

...

plugin:[

new HtmlwebpackPlugin({

...

minify:{

minifyCSS:false, // 是否压缩css

collapseWhitespace:false, // 是否折叠空格

removeComments:true // 是否移除注释

}

})

]

}

 设置了minify,实际会使用另一个插件html-minifier-terser

4、文件大小压缩

对文件的大小进行压缩,减少http传输过程中宽带的损耗。一般使用 CompressionPlugin 插件。

npm install compression-webpack-plugin -D

new CompressionPlugin({

test:/\.(css|js)$/, // 哪些文件需要压缩

threshold:500, // 设置文件多大开始压缩

minRatio:0.7, // 至少压缩的比例

algorithm:"gzip", // 采用的压缩算法

})

5、图片压缩

一般来说在打包之后,一些图片文件的大小是远远要比 js 或者 css 文件要来的大,所以图片压缩较为重要。一般使用loader进行压缩:file-loader 和 image-webpack-loader

配置方法如下:

module: {

rules: [

{

test: /\.(png|jpg|gif)$/,

use: [

{

loader: 'file-loader',

options: {

name: '[name]_[hash].[ext]',

outputPath: 'images/',

}

},

{

loader: 'image-webpack-loader',

options: {

// 压缩 jpeg 的配置

mozjpeg: {

progressive: true,

quality: 65

},

// 使用 imagemin**-optipng 压缩 png,enable: false 为关闭

optipng: {

enabled: false,

},

// 使用 imagemin-pngquant 压缩 png

pngquant: {

quality: '65-90',

speed: 4

},

// 压缩 gif 的配置

gifsicle: {

interlaced: false,

},

// 开启 webp,会把 jpg 和 png 图片压缩为 webp 格式

webp: {

quality: 75

}

}

}

]

},

]

}

6、Tree Shaking

Tree Shaking 是一个术语,在计算机中表示消除死代码,依赖于ES Module的静态语法分析(不执行任何的代码,可以明确知道模块的依赖关系)

在webpack实现Tree shaking有两种不同的方案:

① usedExports:通过标记某些函数是否被使用,之后通过Terser来进行优化的

配置方法也很简单,只需要将usedExports设为true

module.exports = {

...

optimization:{

usedExports: true

}

}

使用之后,没被用上的代码在webpack打包中会加入unused harmony export mul注释,用来告知 Terser 在优化时,可以删除掉这段代码

② sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用

sideEffects用于告知webpack compiler哪些模块时有副作用。

配置方法是在package.json中设置sideEffects属性

如果sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports

如果有些文件需要保留,可以设置为数组的形式

"sideEffects":[

"./src/util/format.js",

"*.css" // 所有的css文件

]

上述都是关于javascript的tree shaking,css同样也能够实现tree shaking

③ css tree shaking

css进行tree shaking优化可以安装 PurgeCss插件

npm install purgecss-plugin-webpack -D

const PurgeCssPlugin = require('purgecss-webpack-plugin')

module.exports = {

...

plugins:[

new PurgeCssPlugin({

path:glob.sync(`${path.resolve('./src')}/**/*`), {nodir:true} // src里面的所有文件

safelist:function(){

return {

standard:["html"]

}

}

})

]

}

paths:表示要检测哪些目录下的内容需要被分析,配合使用glob默认情况下,Purgecss会将我们的html标签的样式移除掉,如果我们希望保留,可以添加一个safelist的属性

7、代码分离

将代码分离到不同的bundle中,之后我们可以按需加载,或者并行加载这些文件。

默认情况下,所有的JavaScript代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载,就会影响首页的加载速度。

代码分离可以分离出更小的bundle,以及控制资源加载优先级,提供代码的加载性能。

这里通过splitChunksPlugin来实现,该插件webpack已经默认安装和集成,只需要配置即可。

默认配置中,chunks仅仅针对于异步(async)请求,我们可以设置为initial或者all

module.exports = {

...

optimization:{

splitChunks:{

chunks:"all"

}

}

}

 splitChunks主要属性有如下:

Chunks:对同步代码还是异步代码进行处理(默认针对异步代码)minSize: 拆分包的大小, 至少为minSize。如果包的大小不超过minSize,这个包不会拆分maxSize: 将大于maxSize的包,拆分为不小于minSize的包minChunks:被引入的次数,默认是1

8、内联chunk

可以通过InlineChunkHtmlPlugin插件将一些chunk的模块内联到html,如runtime的代码(对模块进行解析、加载、模块信息相关的代码),代码量并不大,但是必须加载的

const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin')

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {

...

plugin:[

new InlineChunkHtmlPlugin(HtmlWebpackPlugin,[/runtime.+\.js/]

}

好文链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: