webpack学习(二)高级用法

webpack进阶

treeshaking

作用是在打包时只引入我们依赖的代码,只能作用于import这种静态引入的代码。
我们在package.json文件中,加入"sideEffects": false这样可以告知对所有文件开启treeshaking,如果有些文件我们不想使用treeshaking我们可以传入一个数组来忽略这些文件,如果想删除代码我们只需要将mode改为production会自动帮我们删除没用的代码

代码分割

我们经常会遇到在一个模块中引入一个第三方包多次,比如loadsh,如果我们不做任何配置,默认会在每个引入的文件都将loadsh打进来,造成体积比较大,这时候就要代码分割登场了。提到代码分割,在一般场景下我们会有以下2中场景

  1. 同步代码分割

在我们正常写的js文件中,需要做的就是这种分割,我们在entry中,加入另一个文件入口,这样就会将不同的逻辑代码打成2份文件,但这样会引入另一个问题,比如2个文件都会打进第三方依赖的loadsh,我们还要进一步优化配置,我们加入splitChunks来讲相同的依赖打入另一个文件中,可以看到我们的业务文件体积减少了很多

module.exports = {
  entry: {
    main: path.join(__dirname, './src/index.js'),
    anthor: path.join(__dirname, './src/anthor.js'),
  },
  optimization: {
    splitChunks:{
      chunks: 'all'
    }
  },
}
  1. 异步代码分割

我们可以直接使用webpack提供的import语法来实现异步代码分割,我们修改index.js

function getComponent() {
  return import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => {
    const element = document.createElement('div');
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    return element;
  }).catch(error => 'An error occurred while loading the component');
}
getComponent().then(component => {
  document.body.appendChild(component);
})

为什么我们不做任何配置,异步代码可以执行代码分割,是因为如果我们不做任何配置,webpack会使用默认配置,我在注释中写了这些参数的意思,我们将chunks设置为all就会将同步异步代码都做代码分割

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async', // 默认对异步代码进行分割
      minSize: 30000, // 如果文件超过30kb才会分割
      maxSize: 0, // 一般不做配置
      minChunks: 1, // 当重复引用几次时做分割
      maxAsyncRequests: 5, // 同时异步请求的连接数
      maxInitialRequests: 3, // 初始化加载时页面的请求书
      automaticNameDelimiter: '~', // 命名时使用的连接符
      automaticNameMaxLength: 30,
      name: true,
      cacheGroups: { // 将提取出来的chunk加入缓存组,扫描所有文件后在分组生成chunk
        vendors: {
          test: /[\\/]node_modules[\\/]/, // 匹配node_modules下边的所有模块
          priority: -10 // 分组时的优先级,比如2个chunk都匹配到打包到优先级高的模块里去
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true // 将会检查是否有重复引用的问题
        }
      }
    }
  }
};

懒加载

我们在上边介绍的异步加载,实际上就实现了懒加载,比如还是之前的例子。我们重启项目,可以看到network直到我们点击页面时才会触发加载loadsh生成的chunk

document.addEventListener('click', () => {
  getComponent().then(component => {
    document.body.appendChild(component);
  })
})

function getComponent() {
    return import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => {
      const element = document.createElement('div');
      element.innerHTML = _.join(['Hello', 'webpack'], ' ');
      return element;
    }).catch(error => 'An error occurred while loading the component');
}

预加载

在我们访问页面时我们可以使用懒加载来将一些交互的代码提出来做异步加载,但这同时➡又引出一个问题,就是如果文件比较大,可能会出现反应比较慢的情况这时就要预加载登场了,webpack4的最新版本支持了这个功能

在import中加入import(/*webpackPrefetch: true*/'./click.js'),这样webpack会我们做预加载将文件放到缓存中,其实使用的时link标签rel的prefetch功能

分离css

webpack默认会将css和js代码生成在一起,这从前端渲染上是不好的,我们在生产环境需要分离css先安装npm install --save-dev mini-css-extract-plugin

缓存

在webpack生成的文件我们可以对output中的文件名加入contenthash来保证文件没有改变,生成文件的名一样,这样既可以有效的利用缓存,也可以在文件改变时及时更新,对于html文件常见的做法将http的max-age设为0这样防止了html文件的缓存

打包第三方库

我们开发自己的库时也可以使用webpack打包,只需要将output中增加两个参数,umd表示可以支持commonjs,AMD,和es6module的模块化规范,library表示可以将库挂载到library全局对象上

module.exports = {
  output: {
    library: 'library',
    libraryTarget: 'umd'
  }
}

Dll加速打包

我们想提高打包速度,有一个方法是我们将依赖的第三方模块都打包好不用每次都从新分析打包,webpack提供了现成了DllPlugin,下边我们看一个例子,
我们新建一个webpack.dll.js文件写入以下内容,我们将react和react-dom都一起打包到dll.js文件中,我们还要生成mainfest文件,以便我们使用打包好的js来寻找依赖,我们还配置了library来讲react和react-dom都暴露到dll的全局变量上,使用我们打包好的dll文件也很简单,我们直接在打包的文件中加入dll的引用就可以,在plugins中加入DllReferencePlugin插件,并配置引用mainfest的地址,每次打包时遇到像react,react-dom就可以直接引用dll.js中已经分析好的文件。我们也需要将dll.js也引入我们的html中这里需要一个插件add-asset-html-webpack-plugin,这样就可以看到我们实现了一样的效果但速度减少了一半

// webpack.dll.js
const webpack = require('webpack');
const path = require("path");

module.exports = {
  entry: {
    dll: ['react', 'react-dom']
  },
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: '[name].dll.js',
    library: '[name]'
  },
  plugins: [
    new webpack.DllPlugin({
      name: '[name]',
      path: path.resolve(__dirname, './dist', '[name].mainfest.json'),
    })
  ]
}

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

推荐阅读更多精彩内容