webpack基础使用(五)

十六、加载构建优化
  1. 懒加载
// 按需加载
oBtn.addEventListener('click', () => {
  import('./utils').then(({ default: element }) => {
    console.log(element)
    document.body.appendChild(element)
  })
})
  1. 预获取 & 预读取
// 按需加载
oBtn.addEventListener('click', () => {
  import(
    /* webpackChunkName:'utils' */
    /* webpackPreload:true */
    './utils').then(({ default: element }) => {
      console.log(element)
      document.body.appendChild(element)
    })
})

//  /* webpackPrefetch:true */

与 prefetch 指令相比,preload 指令有许多不同之处:

preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。
浏览器支持程度不同。

preload 可以使用在首页很可能需要点击的按钮上面

  1. CDN优化
    优化打包速度, 使用CDN加载提高性能.
// index.html
  <!-- cdn可以在对应官网查找 -->
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>

// webpack.common.js
output: { 
    // publicPath: '配置自己的CDN地址'
  },
    // 排除lodash,加快打包速度
    // 使用CDN加载lodash提高性能
    // '_'是固定写法
    externals: {
      lodash: '_'
    }
  1. dll库
    把大的, 不经常变的打包成一个dll库, 然后使用方直接加载使用。
const path = require('path')
const webpack = require('webpack')
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
  mode: "production",
  // 需要打包的东西
  entry: {
    react: ['react', 'react-dom']
  },
  output: {
    // 输出路径
    path: path.resolve(__dirname, 'dll'),
    filename: 'dll_[name].js',
    // 暴露从入口导出的内容, 给使用地方的命名
    library: 'dll_[name]'
  },
  optimization: {
    minimizer: [
      new TerserPlugin({
        // 使用Terser压缩
        // minimize: true,
        // 去除注释文件
        extractComments: false
      }),
    ],
  },
  plugins: [
    // 生成dll的插件
    new webpack.DllPlugin({
      name: 'dll_[name]',
      // manifest负责映射到具体文件
      path: path.resolve(__dirname, './dll/[name].manifest.json')
    })
  ]
}
  1. 使用dll库
    注意dll库只是帮助我们避免打包了, js里面导入文件不变。
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')

const commonConfig = {
  /*省略*/
  plugins: [
    new webpack.DllReferencePlugin({
      context: resolveApp('./'),
      // 相对于context的路径
      manifest: resolveApp('./dll/react.manifest.json')
    }),
    // 
    new AddAssetHtmlPlugin({
      // 这个插件目前之后在html里面找auto目录
      outputPath: 'auto',
      // 拷贝一份到dist, 同时添加html引用, html从auto里面找
      filepath: resolveApp('./dll/dll_react.js')
    })
  ]
}
  1. css抽取和压缩
    css 150KB再考虑分包,因为这样增加一次加载。
// webpack.prod.js
// 抽取独立css
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
// 压缩css
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")

module.exports = {
  mode: 'production', 
  optimization: {
    minimizer: [
      new CssMinimizerPlugin()
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[hash:8].css'
    })
  ]
}

// webpack.common.js
// 抽取独立css
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
          {
            test: /\.css$/,
            use: [
              isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
              {
                loader: 'css-loader',
                options: {
                  // 代表向前找一个loader处理 
                  esModule: false
                }
              }, 'postcss-loader'
            ]
          }
  1. 作用域提升
    作用域提升只能知道esModule的语法
// webpack.prod.js
const webpack = require('webpack')

module.exports = {
  mode: 'production',
  plugins: [
    /* 省略 */
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
}
  1. TreeShaking
    a. usedExports 标记不需要使用的代码
optimization: {
   // 标记不需要使用的代码:/* unused harmony export foo2 */
    usedExports: true,
    // 树摇, TerserPlugin移除不使用的代码
    minimize: true,
  }

b. sideEffects 识别副作用
对于不需要使用的类,有选择的跳过,去除对应副作用

// utils.js
window.utils = '1111'
// index.js
import './utils'
//1. 是可以打印的
console.log(window.utils, '<------')

// package.json 代表代码都是没有副作用的, 如果没有使用就移除
"sideEffects": false
//2. 打印为undefined
console.log(window.utils, '<------')

// package.json 代表代码都是有副作用的,即使没有使用也不能移除
//3. 使用副作用
"sideEffects": [
    "./src/title.js"
  ]

正常Css文件,我们是需要使用副作用的 ,可以在package.json里面配置,不过一般在webconfig文件里面配置


image.png

c. PurgeCSSPlugin 针对Css文件进行树摇
yarn add purgecss-webpack-plugin glob --dev
注意及时代码注释,主要注释里面有对应标签,也算使用。

// webpack.prod.js

const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const resolveApp = require('./paths')
const glob = require('glob')

module.exports = {
  plugins: [
    new PurgeCSSPlugin({
      // 查找src里面所有文件
      paths: glob.sync(`${resolveApp('./src')}/**/*`, { nodir: true }),
      safelist: function () {
        return {
          // 下面css标签不会被树摇
          standard: ['body', 'html', 'ef']
        }
      }
    })
  ]
}
  1. 压缩部署,http请求的时候节省资源
    yarn add compression-webpack-plugin --dev
// webpack.prod.js

const CompressionPlugin = require("compression-webpack-plugin")

module.exports = {
  plugins: [
      new CompressionPlugin({
      // 只压缩css 和 js 文件
      test: /\.(css|js)$/,
      // 默认0.8 只有压缩比到0.8才生成压缩文件
      minRatio: 0.8,
      // 文件大小, 开始压缩
      threshold: 0,
      // 压缩格式
      algorithm: 'gzip'
    })
  ]
}
  1. inlineChunkHtmlPlugin 可以向Html注入内容
    有时候比较小的文件,可以直接在html中使用,而不需要引入一次。
    yarn add inline-chunk-html-plugin --dev
// webpack.prod.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  plugins: [
      // 把runtime文件直接注入到 需要的Html文件中
      new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime.*\.js/])
  ]
}
  1. webpack 打包 三方库
  output: {
    filename: 'sy_utils.js',
    path: path.resolve(__dirname, 'dist'),
    /// umd 所有模块化结合
    libraryTarget: 'umd',
    // library使用的名称
    library: 'syUtil', 
    // 调用全局变量
    globalObject: 'this'
  }
  1. 打包时间和内容分析
// 时间分析
// webpack.common.js
// 注意兼容性, 需要mini-css-extract-plugin降级到1.3.6
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
const smp = new SpeedMeasurePlugin()
module.exports = (env) => {
  /**/
  return smp.wrap(mergeConfig)
}

// 内容分析
// webpack.prod.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

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

推荐阅读更多精彩内容