webpack-4-性能优化

1. 跟上技术的迭代(node,npm,yarn)

在项目中尽可能 使用新的webpack、node等.新版本内可能做了一些性能上的优化,更好用一些 。

2. 在尽可能少的 模块上使用loader。

如合理的使用include和exclude

...
module.exports = {
    ...
    module: {
        rules: [{ 
            test: /\.js$/, 
            exclude: /node_modules/, //一定要加,不然会降低打包速度
            use: ['babel-loader','eslint-loader']
        }]
    },
}

3. plugin尽可能精简并确保可靠。开发环境无用插件剔除

开发模式下未使用css压缩的插件,生产模式下未使用热更新的插件,为的就是减少插件 的使用,提升性能。

//webpack.prod.js
 plugins: [new MiniCssExtractPlugin({
        filename: '[name].css'
    })]
//webpack.dev.js
 plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]

插件尽可能使用官方推荐过的,性能比较好的或社区 验证过的插件 。

4. import时后缀名是否要加?extensions和mainFiles

const commonConfig = {
    ...
    resolve:{
        extensions:['.js','.jsx'] ,//如果import时没有指定文件后缀 ,就先找.js文件
        mainFiles:['index','main'] //如果导入时不加文件名和后缀,指定先去找名为index文件,没有的话再去找名为main的文件。
    }
}
import Home from './home'; //js、jsx文件可以不加
import  './style.css'; //css文件加上后缀名
import Child from './child/'; //配置了mainFiles,引入时不加文件名,不可取

js、ts、jsx等逻辑代码可以不加后缀,.jpg、.svg、.css等建议导入时加上 文件后缀,因为类型多了,一个类型一个类型查找就费时间了。mainFiles能不配就不配,影响打包性能。

5. 控制webpack打包生成的文件大小

tree shaking
splitchunks

6. thread-loader,parallel-webpack,happypack多进程打包。默认是单进程,同事利用多个 cpu。

7. 合理使用sourcemap,sourcemap越详细打包越慢

8. 结合stats分析打包结果

9. 开发环境内存编辑。不会生成dist目录,放在内存里边,内存比硬盘读取快的多

10.DllPlugin

也可以参考臂展某个老师的视频,很清晰:https://www.bilibili.com/video/BV1eC4y147RX/?spm_id_from=333.337.search-card.all.click&vd_source=8d08ffbe793f2ec363ae13e64d626a61
第三方模块的代码并不会变,但是每次打包都会去分析一次再融合成一个文件打包出来的,默认配置如此。
如果单独把这些第三方包打包成一个文件,只分析一次 ,之后再次打包不再去分析,直接用上次分析好的结果,达到第三方包只打包一次,这是个很好的思路。

 optimization: {
        splitChunks: {
            cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10,
                },
            }
        }
    },

准备工作:创建一个新项目mytest-dll,生产和开发分开配置,入口文件用到了react、react-dom和lodash等第三方包

5.1. 生成单独三方包文件 ,配置DllPlugin生成映射文件

单独写个三方包配置文件webpack.dll.js,生成一个js文件,暴露到全局,再用插件生成一个对应的包映射文件。 npm run build:dll

//webpack.dll.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
    mode:'production',
    entry:{
        vendors:['react-dom','react','lodash'], //用到的第三方包,生成 一个js文件
    },
    output:{
        filename:'[name].dll.js', //包名将是vendors.dll.js
        path:path.resolve(__dirname,'../dll'), //输出到dll目录
        library:'[name]',//entry叫什么名,暴露的全局对象就叫什么名
    },
    plugins:[
         new webpack.DllPlugin({ //生成import三方包请求 到module id的映射文件
             name:'[name]', //entry名
             path:path.resolve(__dirname,'../dll/[name].manifest.json') //映射文件的生成路径
         })
    ]
}
//package.json
  "scripts": {
    "dev-build": "webpack --config ./build/webpack.common.js",
    "build": "webpack --env.production --config ./build/webpack.common.js",
    "build:dll": "webpack --config ./build/webpack.dill.js",
    "start": "webpack-dev-server --config ./build/webpack.common.js"
  },
5.2. add-asset-html-webpack-plugin嵌入dll.js文件到html中

把这个vendors.dill.js通过script标签插入到HtmlWebpackPlugin生成的index.html中,安装基于HtmlWebpackPlugin的一个插件 npm i add-asset-html-webpack-plugin@3.1.2 -D

...
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const commonConfig = {
    ...
    plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname,'../src/index.html')
        }),
        new AddAssetHtmlWebpackPlugin({ //把生成的vendors.dll.js通过script标签嵌入html中
            filepath: path.resolve(__dirname,'../dll/vendors.dll.js')
        })
    ]
}
...
5.3. 配置DllReferencePlugin

用插件在包导入的时候,先去映射文件里查找是否有该包,有就使用dll导出的包,没有再去已分析出的包中找。 npm run build

...
const path = require('path')
const webpack = require('webpack')
const commonConfig = {
    ...
    plugins: [
        new webpack.DllReferencePlugin({  //import包时,先去manifest.json中看有没有这个包,有就用全局变量的,没有再去node_modules里找
            manifest:path.resolve(__dirname,'../dll/vendors.manifest.json')
        })
    ]
}
...
5.4 项目比较复杂,三方包生成多个文件
//webpack.dll.js
module.exports = {
    entry:{
        vendors:['react-dom','react'],
        lodash:['lodash'],
    }
}
//webpack.common.js
const path = require('path')
const fs = require('fs')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

function getPlugins() {
    var plugins = [
        new CleanWebpackPlugin(['dist'], {
            root: path.resolve(__dirname, '../'), //指定项目根目录,默认清空下会认为当前文件所在的目录为根目录。
        }),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, '../src/index.html')
        })
    ]
    const files = fs.readdirSync(path.resolve(__dirname, '../dll')) //读取文件夹内的文件名
    console.log(files)
    files.forEach((filename) => {
        if (/.\.dll\.js$/.test(filename)) {
            plugins.push(
                new AddAssetHtmlWebpackPlugin({ //把生成的vendors.dll.js通过script标签嵌入html中
                    filepath: path.resolve(__dirname, '../dll', filename)
                })
            )
        } else if (/.\.manifest\.json$/.test(filename)) {
            plugins.push(
                new webpack.DllReferencePlugin({
                    manifest: path.resolve(__dirname, '../dll',filename)
                })
            )
        }
    })
    return plugins
}
const commonConfig = {
    ...
    plugins: getPlugins()
// plugins: [
    //     new CleanWebpackPlugin(['dist'], {
    //         root: path.resolve(__dirname, '../'), //指定项目根目录,默认清空下会认为当前文件所在的目录为根目录。
    //     }),
    //     new HtmlWebpackPlugin({
    //         template: path.resolve(__dirname,'../src/index.html')
    //     }),
    //     new AddAssetHtmlWebpackPlugin({ //把生成的vendors.dll.js通过script标签嵌入html中
    //         filepath: path.resolve(__dirname,'../dll/vendors.dll.js')
    //     }),
    //     new webpack.DllReferencePlugin({
    //         manifest:path.resolve(__dirname,'../dll/vendors.manifest.json')
    //     }),
    //     new AddAssetHtmlWebpackPlugin({ //把生成的lodash.dll.js通过script标签嵌入html中
    //         filepath: path.resolve(__dirname,'../dll/lodash.dll.js')
    //     }),
    //     new webpack.DllReferencePlugin({
    //         manifest:path.resolve(__dirname,'../dll/lodash.manifest.json')
    //     })
    // ]
}

5.5 也可以把打好的库放到cdn上

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容