0

0

0

修罗

站点介绍

只有了解事实才能获得真正的自由

webpack 优化配置

修罗 2020-08-02 1575 0条评论 前端资源构建 webpack

首页 / 正文

webpack性能优化

  • 开发环境性能优化
  • 生产环境性能优化

开发环境性能优化

  • 优化打包构建速度

    • HMR
  • 优化代码调试

    • source-map

生产环境性能优化

  • 优化打包构建速度

    • oneOf
    • babel缓存
    • 多进程打包
    • externals
    • dll
  • 优化代码运行的性能

    • 缓存(hash-chunkhash-contenthash)
    • tree shaking
    • code split
    • 懒加载/预加载
    • pwa

第 5 章:webpack 优化配置

5.1 HMR

HMR: hot module replacement 热模块替换 / 模块热替换
作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块) 极大提升构建速度

样式文件:可以使用HMR功能:因为style-loader内部实现了~

js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码
注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。

html文件: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了~ (不用做HMR功能)解决:修改entry入口,将html文件引入

开启HMR功能

hot: true

webpack.config.js

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: ['./src/js/index.js', './src/index.html'],
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        // 处理less资源
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        // 处理css资源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        // 处理图片资源
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          // 关闭es6模块化
          esModule: false,
          outputPath: 'imgs'
        }
      },
      {
        // 处理html中img资源
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        // 处理其他资源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true,
    // 开启HMR功能
    // 当修改了webpack配置,新配置要想生效,必须重新webpack服务
    hot: true
  }
};

js支持hmr

if (module.hot) {
  // 一旦 module.hot 为true,说明开启了HMR功能。 --> 让HMR功能代码生效
  module.hot.accept('./print.js', function() {
    // 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。
    // 会执行后面的回调函数
    print();
  });
}

1596708872256.png

1596709124890.png

5.2 source-map

source-map:

一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)

[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

使用:在配置文件加入(配置的一次层对象属性)

devtool: 'eval-source-map'

内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快

source-map:外部
错误代码准确信息 和 源代码的错误位置

inline-source-map:内联
只生成一个内联source-map
错误代码准确信息 和 源代码的错误位置

hidden-source-map:外部
错误代码错误原因,但是没有错误位置
不能追踪源代码错误,只能提示到构建后代码的错误位置

eval-source-map:内联
每一个文件都生成对应的source-map,都在eval
错误代码准确信息 和 源代码的错误位置

nosources-source-map:外部
错误代码准确信息, 但是没有任何源代码信息

cheap-source-map:外部
错误代码准确信息 和 源代码的错误位置
只能精确到行

cheap-module-source-map:外部
错误代码准确信息 和 源代码的错误位置
module会将loader的source map加入

开发环境:速度快,调试更友好
速度快(eval>inline>cheap>...)

eval-cheap-souce-map
eval-source-map

调试更友好

souce-map
cheap-module-souce-map
cheap-souce-map

--> eval-source-map / eval-cheap-module-souce-map

生产环境:源代码要不要隐藏? 调试要不要更友好
内联会让代码体积变大,所以在生产环境不用内联
nosources-source-map 全部隐藏
hidden-source-map 只隐藏源代码,会提示构建后代码错误信息

--> source-map / cheap-module-souce-map

5.3 oneOf

oneOf:loader 只会匹配一个

1596712339968.png

5.4 缓存

babel缓存 --> 让第二次打包构建速度更快

cacheDirectory: true

1596714352131.png

文件资源缓存

hash: 每次wepack构建时会生成一个唯一的hash值。([hash:10]拿hash值前十位)
问题: 因为js和css同时使用一个hash值。
如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)

chunkhash(根据入口文件引入的资源(依赖)都会生成一个chunk):

根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
问题: js和css的hash值还是一样的
因为css是在js中被引入的,所以同属于一个chunk

contenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样
--> 让代码上线运行缓存更好使用

出口文件

1596714527404.png

css文件

1596714566792.png

图片文件

1596714599824.png

5.5 tree shaking

摇掉树上死掉的叶子(没用到的代码)

tree shaking:去除无用代码

前提:1. 必须使用ES6模块化  2. 开启production环境
作用: 减少代码体积

1596721808586.png

在package.json中配置
"sideEffects": false: 所有代码都没有副作用(都可以进行tree shaking)
问题:可能会把css / @babel/polyfill (副作用)文件干掉,因为直接引入没有使用
"sideEffects": [".css", ".less"]

5.6 code split

可以将一个文件分隔为多个文件,按需加载(js)

1、

1596724739983.png

构建

1596724833021.png

2、splitChunks可以将node_modules中代码单独打包一个chunk最终输出

​ 多入口还会自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk

(js1中加载了jQuery,js2中也加载了jQuery,没有配置splitChunks会加载两次,打包出来的两个js文件都很大。把jQuery整成单独一个文件)

1596725016795.png

3、

通过js代码,让某个文件被单独打包成一个chunk

import动态导入语法:能将某个文件单独打包(这里打包当前目录下text.js)

1596725556875.png

加入保证node_modules单独打包一个chunk

1596725671665.png

5.7 lazy loading

懒加载:当文件需要使用时才加载

1596723993760.png

预加载 prefetch:会在使用之前,提前加载js文件

正常加载可以认为是并行加载(同一时间加载多个文件)

预加载 prefetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源

1596724036394.png

5.8 pwa

PWA: 渐进式网络开发应用程序(离线可访问)

workbox --> workbox-webpack-plugin

npm install --save-dev workbox-webpack-plugin

插件中配置

new WorkboxWebpackPlugin.GenerateSW({
/*
  1. 帮助serviceworker快速启动
  2. 删除旧的 serviceworker

  生成一个 serviceworker 配置文件~
*/
    clientsClaim: true,
    skipWaiting: true
})

index.js写如下代码

/*
  1. eslint不认识 window、navigator全局变量
    解决:需要修改package.json中eslintConfig配置
      "env": {
        "browser": true // 支持浏览器端全局变量
      }
   2. sw代码必须运行在服务器上
      --> nodejs
      -->
        npm i serve -g
        serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去
*/
// 注册serviceWorker
// 处理兼容性问题
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(() => {
        console.log('sw注册成功了~');
      })
      .catch(() => {
        console.log('sw注册失败了~');
      });
  });
}

eslint配置

1596727715786.png
安装服务器

npm i serve -g

运行服务器

1596728159578.png
没有网也能加载,搜狗浏览器不支持

1596728053478.png

5.9 多进程打包

进程启动大概为600ms,进程通信也有开销。

只有工作消耗时间比较长,才需要多进程打包

1596728676016.png

5.10 externals

场景:有些包通过CDN引入

1596728895265.png

5.11 dll

动态连接库。

使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包

当你运行 webpack 时,默认查找 webpack.config.js 配置文件

需求:需要运行 webpack.dll.js 文件

webpack --config webpack.dll.js

webpack.dll.js

const { resolve } = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {
    // 最终打包生成的[name] --> jquery
    // ['jquery'] --> 要打包的库是jquery
    jquery: ['jquery'],
  },
  output: {
    filename: '[name].js',
    path: resolve(__dirname, 'dll'),
    library: '[name]_[hash]' // 打包的库里面向外暴露出去的内容叫什么名字
  },
  plugins: [
    // 打包生成一个 manifest.json --> 提供和jquery映射
    new webpack.DllPlugin({
      name: '[name]_[hash]', // 映射库的暴露的内容名称
      path: resolve(__dirname, 'dll/manifest.json') // 输出文件路径
    })
  ],
  mode: 'production'
};

1596753628877.png

安装库

yarn add add-asset-html-webpack-plugin -D

webpack.config.js

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    // 告诉webpack哪些库不参与打包,同时使用时的名称也得变~
    new webpack.DllReferencePlugin({
      manifest: resolve(__dirname, 'dll/manifest.json')
    }),
    // 将某个文件打包输出去,并在html中自动引入该资源
    new AddAssetHtmlWebpackPlugin({
      filepath: resolve(__dirname, 'dll/jquery.js')
    })
  ],
  mode: 'production'
};

这样打包自动引入

1596754171280.png

这样不会打包出来

1596754345165.png

评论(0)


最新评论

  • 1

    1

  • 1

    1

  • -1' OR 2+158-158-1=0+0+0+1 or 'TKCTZnRa'='

    1

  • 1

    1

  • 1

    1

  • 1

    1

  • 1

    1

  • @@5Qa2D

    1

  • 1

    1

  • 1

    1

日历

2025年09月

 123456
78910111213
14151617181920
21222324252627
282930    

文章目录

推荐关键字: Linux webpack js 算法 MongoDB laravel JAVA jquery javase redis