webpack5

官方文档:
https://www.webpackjs.com/concepts/

why webpack

1.现代web开发‘问题’

  • 采用模块化开发
  • 使用新特性提高效率保证安全性
  • 实时监听开发过程使用热更新
  • 项目结果打包压缩优化

使用webpack实现项目工程化

2. webpack上手

为现代javascript应用提供静态模块打包的工具

  • 打包:将不同类型资源按模块处理进行打包
  • 静态:打包后最终产出静态资源
  • 模块:webpack支持不同规范的模块化开发。

全局安装:npm install --global webpack
查看版本:webpack --version
webpack 5.51.1

使用全局的webpack并不合适,因为每个人本地安装的版本并不相同,因此需要使用局部的webpack打包。

  • 默认会找src/index.js开始打包。
  • 打包:npx webpack
  • 自定义打包入口 npx webpack --entry ./src/main.js
  • 希望打包的文件放在指定的目录中 npx webpack --entry ./src/main.js --output-path ./build
  • 命令简写: 在package.json中配置:
"scripts": {
    "build": " npx webpack --entry ./src/main.js --output-path ./build"
  },

书写配置文件

  • webpack.config.js
const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'build.js',
    path: path.resolve(__dirname, 'dist')
  }
}
4. webpack 依赖图

1.新添加的js文件,如果也想打包,则需要加入到主入口文件中,构成依赖
2. 自定义配置文件名:lg.webpack.js
在packaje.json中配置:

"scripts": {
    "build": "webpack --config lg.webpack.js"
  },

lg.webpack.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
}
5. CSS-Loader

在使用webpack的过程中,发现并不是可以处理所有类型的文件,因此需要使用loader对它进行转换。
loader要想使用,首先需要安装,然后具体的loader需要去查找。然后在配置文件中进行配置。

  1. 为什么需要使用loader?
    loader是必须的。loader起到一个转换的功能
  2. loader是什么?
    是一个模块,里面导出一个函数,这个函数的功能起到一个转换的作用,webpack默认只识别js语法,其他的语法不能识别。因此需要转换成webpack可以识别的语法。
  3. css-loader案例
    npm i css-loader --save-dev

1.行内loader的使用

// 行内loader(一般不使用)
// css-loadder只是将当前css语法处理为js可以识别的语法,但是并不能把样式放在页面上进行使用。
// 使用方式1
// import 'css-loader!../css/login.css'
// 使用方式2 并且需要在webpack.config.js 中进行配置
import '../css/login.css'

function login() {
  const oH2 = document.createElement('h2')
  oH2.innerHTML = '拉勾教育前端'
  oH2.className = 'title'
  return oH2
}

document.body.appendChild(login())

webpack.config.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      // 3中书写方式
      // 适合多个loader一起使用
      // {
      //   test: /\.css$/, // 一般就是一个正则表达式,用于匹配我们需要处理的文件类型
      //   use: [
      //     {
      //       loader: 'css-loader'
      //     }
      //   ]
      // },
      // 简写1
      // {
      //   test: /\.css$/,
      //   loader: 'css-loader'
      // },
      // 简写2
      {
        test: /\.css$/,
        use: ['css-loader']
      }
    ]
  }
}
6.style-loader 使用
  • 让我们用css-loader处理的css,最终可以在页面上显示出效果。
    安装:npm i style-loader --save-dev
    使用:webpack.config.js
module: {
    rules: [
      {
        test: /\.css$/,
        // 处理的顺序,如果是一行:从右向左,如果换行:从下向上。
        use: ['style-loader', 'css-loader']
      }
    ]
  }
7. less-loader

在项目中使用less
./longin.less

@bgColor: seagreen;
@fontSize: 100px;

.title {
  background-color: @bgColor;
  font-size: @fontSize;
}

在项目中引入:

import '../css/login.less'

1.安装:npm install less less-loader -D
2.使用:
webpack.config.js

module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/,
      // 先使用less-loader把less转换成css,css还是浏览器不能识别的,还需要使用css-loader,style-loader
        use: ['style-loader', 'css-loader', 'less-loader']
      }
    ]
  }
8. browserslitrc 工作流程
  1. 兼容性:新特性/新语法的支持( css, js)
  2. 如何实现兼容操作?
  3. 到底要兼容哪些平台?
  4. caniuse.com .可以查到浏览器的市场占用率

.browserslitrc

  • > 1% 的含义:市场占有率>1%的浏览器都能被兼容到
  • last 2 version :某一个浏览器的最新2个版本。
  • default: 市场占有率>0.5%,最新的2个版本。
  • dead:废弃的平台。(24个月没有维护的平台)

2种配置方法:

  1. 中在package.js
"browserslistrc": [
">1%",
"last 4 version",
"not dead"
]

执行 npx browserslist

  1. .browserslistrc
> 1% 
last 2 version
not dead
9. postcss 工作流程
  • 查看样式在浏览器中的兼容性:http://autoprefixer.github.io/
  • postcss是什么:通过javascript来转换样式的工具。
    安装:npm i postcss -D
  • 在终端中使用postcss需要安装postcss-cli:npm i postcss-cli -D
  • 安装:npm i autoprefixer -D。进行具体的样式转换。
    // -o :output
    // -o ret.css :输出目录
    // ./src/css/test.js 需要处理的路径
    执行命令查看效果:npx postcss --use autoprefixer -o ret.css ./src/css/test.js

postcss: 整体的解析器
autoprefixer:指的是具体的功能,可以对样式做一个前缀的添加
postcss-cli:想在命令行中使用命令执行.

10.postcss-loader 处理兼容
  • 如果有很多文件要处理,不可能还使用命令行来操作,因此要借助:postcss-loader来处理。
  • postcss-loader和.browserslitrc是搭配使用的。
  • 如果想要兼容的更多,可以调整.browserslitrc文件中的配置项,例如>1%调整为>0.1%,打包出来的css是不一样的。
  • npm i postcss-loader -D
  • npm i autoprefixer -D
    postcss-loader在css-loader之前进行工作,需要在代码之前加上前缀,处理之后交给css-loadre。
    配置postcss-loader:
    webpack.config.js
rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  require('autoprefixer')require('postcss-preset-env'),
                ]
              }
            }
          }
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  require('autoprefixer'),
                  require('postcss-preset-env')
                ]
              }
            }
          },
          'less-loader'
        ]
      }
    ]
  • 例如:css颜色的设置:color:#12345678,后面的两位是透明度,postcss-loader是不能解析的,新出的写法。因此出现了postcss-preset-env。处理css的集合。
  • 集合了很多现代css转换需要做的集合:npm i postcss-preset-env -D

预设
插件集合

  • autoprefixer已经被包含在了postcss-preset-env中了,因此可以不需要引入:autoprefixer
  • 可以发现代码同样的配置写了2遍,可以很方便的进行添加和管理。因此可以用配置文件的写法:
  • postcss.config.js(文件的名称不能随意修改,默认的就会找这个文件)
module.exports = {
  plugins: [
    require('postcss-preset-env')
    // require('autoprefixer')
  ]
}

webpack.config.js

rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      }
    ]

npm run build查看样式。

11. importLoaders 属性

importLoaders:
解析postcss-loader解析后,一直执行,但是有的文件不会被postcss-loader处理问题
1: 表示调用几次。

module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          }
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      }
    ]
12.file-loader 处理图片
  • 2种图片的引入方式
  1. image src
  2. background-image url
  • npm i file-laoder -D
/**
 * 打包图片:
 *  - img src
 *    + 使用 require 导入图片,此时如果不配置 esModule: false ,则需.default 导出
 *    + 也可以在配置当中设置 esModule: false
 *    + 采用 import xxx from 图片资源,此时可以直接使用 xxxx
 *  - background url
 */

// esModule: false。为了解决:使用background引入图片时,引入的背景图不能显示问题。

rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: 'img/[name].[hash:6].[ext]',
              // outputPath: 'img'
            }
          }
        ]
      }
    ]
/**
 * [ext]: 扩展名
 * [name]: 文件名
 * [hash]: 文件内容
 * [contentHash]:
 * [hash:<length>]
 * [path]:
 */
14.url-loader 处理图片

npm i url-loader -D

  • 两者的不同:
    file-loader: 将图片资源直接拷贝到要打包的目录。
    url-loader: 把我们当前要打包出来的图片资源以base64uri的方式去加载到代码中去。打包出来的文件,发现找不到图片。好处是:减少请求的次数,不好:如果文件过大,会出现请求的时间过长,在首屏影响性能和体验。
rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        use: [
          {
            loader: 'url-loader',
            // 设置图片名称与输出 tscproj
            options: {
              name: 'img/[name].[hash:6].[ext]',
              limit: 25 * 1024
            }
          }
        ]
      }
    ]
/**2者区别:
 * 01 url-loader base64 uri 文件当中,减少请求次数
 * 02 file-loader 将资源拷贝至指定的目录,分开请求
 * 03 2者之间的联系:url-loader 内部其实也可以调用 file-loader。
 * 04 limit:决定了:以哪种方式加载。如果大于这个值,就做做拷贝,如果没有超过这个值,就是base64 uri的方式加载
 *
 */
15. asset 处理图片
  • 卸载url-loader, file-loader
  • 使用asset。asset是webpack内置的功能,因此不需要安装。
  • asset:4种配置。
  • type: ‘asset /resource’ 功能和file-loader是一样的
  • type: ‘asset/inline’ 功能和uri-loader一样。
  • type: ‘asset/source’ 功能和 raw-loader一样。
  • asset
    webpack.config.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    // 重定向输出方式2.一般呢不会这样配置。因为是:全局的配置。字体也会走这样的打包路线。
    // assetModuleFilename: "img/[name].[hash:4][ext]"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        // type: 'asset/resource',
        // type: 'asset/inline',
        generator: {
        // 重定向输出方式1
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
         // 如果图片的大小超过maxSize的值,就走asset/resource
         // 如果图片的大小小于maxSize的值,就走asset/inline
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      }
    ]
  }
}
16. asset 处理图标字体
rules: [
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      }
    ]
17. webpack插件使用
  • loader: 转换,特定类型
  • plugin:做更多的事情。可以贯穿整个webapck生命周期。

每次打包时清除上次打包的文件。

  • npm install clean-webpack-plugn -D
  • 在webpack.config.js中使用
    webpakc.confg.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
	plugins: [
    	new CleanWebpackPlugin()
  	]
}
18.html-webapck-plugin 使用
  • 自定义html模版
  • npm install html-webpack-plugin - D
  • 在webpack.config.js中使用
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { DefinePlugin } = require('webpack')
module.exports = {
	plugins: [
    	new HtmlWebpackPlugin({
	      // title
	      title: 'html-webpack-plugin',
	      // 定义自己打包的html 模版
	      template: './public/index.html'
	    }),
	    // 内置的插件 。定义iocn。
	    // 注意:BASE_URL的赋值。
	    new DefinePlugin({
	      BASE_URL: '"./"'
	    })
  	]
}

  • 创建模版文件
    ./public/index.html
<!DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">

  <!-- icon -->
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">

  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
        Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
</body>

</html>

在这里插入图片描述

19.copy-webpack-plugin
  • npm install copy-webpack-plugin -D
  • 在webpack.config.js中使用
const CopyWebpackPlugin = require('copy-webpack-plugin')

plugins: [
    new CopyWebpackPlugin({
      // 拷贝规则
      patterns: [
        {
          // 期望从哪里开始拷贝
          from: 'public',
          // 拷贝到哪里 to可以不写。默认是:上面的output.path的值
          // to: 'dist',
          // 可以指定规则拷贝的时候,不需要拷贝的地方
          globOptions: {
            // '**/':表示从from设置的目录开始
            ignore: ['**/index.html']
          }
        }
      ]
    })
  ]
20. babel 工作的过程和使用
  • 为什么需要 Babel。 – 处理js兼容
    我们在做react/vue开发时,用到的jsx语法,ts语法,es6+ 语法,不能直接在浏览器平台使用,如果想在浏览器平台直接使用,那么中间就需要一个转换的过程,需要一个东西来处理js,类似于postcss兼容css。
    babel是一个工具,本身不具备任何功能。
  • @babel/core:核心功能。
  • npm install @babel/core -D 作用:非es5的代码专程浏览器可以识别的。
  • npm install @babel/cli -D 。 作用:命令行工具。在命令行中可以使用。可以直接在命令行中执行:npx babel
  • npx babel src --out-dir build.
  • src:开始转换的入口。 --out-dir build: 输出的目录。
  • npm install --save-dev @babel/plugin-transform-arrow-functions
  • 执行命令:npx babel src --out-dir build --plugins=@@babel/plugin-transform-arrow-functions. 查看代码可以发现箭头函数被转换成了普通函数。

使用:

  • npm install @babel/core -D
  • npm install @babel/cli -D
  • npm install @babel/plugin-transform-arrow-functions -D. // 箭头函数转换成普通函数
  • npm install @babel/plugin-transform-block-scoping -D。 // const. - > 转换成var
  • 书写伪代码:
const title = 'wode'
const foo = () => {
  console.log(title)
}
foo()
  • 执行打包命令: npx babel src --out-dir build --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-block-scoping
  • 查看打包出来的文件
const title = 'wode';

const foo = function () {
  console.log(title);
};

foo();

在这里插入图片描述

直接使用:npm install @babel/plugin-preset-env -D。可以完成js代码的转换。

  • 执行命令: npx babel src --out-dir build --plugins=@babel/preset-env。发现可以完成以上箭头函数,变量…等转换。
21. babel-loader 使用
  • npm install babel-loader -D 拷贝一份js代码,什么也不做。打包之后的代码:箭头函数仍然书箭头函数,const仍然是const,并没有做转换。

  • npm install @babel/plugin-preset-env -D。 @babel/plugin-preset-env对代码进行转换

  • bebl-loader 相关的配置文件有2中方式书写:
    1. 方式1: 直接在webpack.config.js中配置
    2. 在webpack.config.js + 创建babel.config.js文件 (一般采用的方式)

方式1 :在webpack.config.js中进行配置:

rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-env',
                { targets: 'chrome91' } // 兼容的浏览器版本设置
              ]
            }
          }
        ]
      }
    ]
  • 方式2: webpack.config.js + 新建babel.config.js文件
    webpack.config.js:
rules: [
      {
        test: /\.js$/,
        use: ['babel-loader']
      }
    ]

新建babel.config.js文件

module.exports = {
  presets: ['@babel/preset-env']
}

babel包:https://github.com/babel/babel/tree/main/packages

注意:兼容性处理:需要配合.browserslistrc这个文件一块设置使用。

22. polyfill 配置

更加方便的处理js的兼容性操作
webpack4默认自己加进去了,打包出来的代码包非常的大。webpack5默认情况下被移除掉了,用到了里面的东西,需要自己安装和配置。

  • polyfill到底是什么?
    可以转换一些es6的新语法,例如:promise,aysnc…
  • npm install @babel/polyfill --save. 开发依赖。 按需配置。
  • 官方文档: https://babeljs.io/docs/en/babel-polyfill
  • .browserslistrc 指出要兼容哪些浏览器。
  • babel.config.js. 怎么兼容之处的浏览器,具体的做一些配置。

babel.config.js配置:

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        // false: 不对当前的JS处理做 polyfill 的填充
        // usage: 依据用户源代码当中所使用到的新语法进行填充
        // entry: 依据我们当前筛选出来的浏览器决定填充什么
        useBuiltIns: 'entry',
        corejs: 3 // 版本3
      }
    ]
  ]
}
23.webpack-dev-server配置

开启本地服务器:

  • 配置:webpack-dev-server
  • npm install --save-dev webpack-dev-server
  • 修改package.json
  • 会在开始一个8080端口的监听
    package.json
"scripts": {
    "serve": "webpack serve --config lg.webpack.js"
  },

原理:把数据都写在内存里面,内存的操作肯定比本地的硬盘操作快。

24.webpack-dev-middleware 使用

文档介绍:https://www.webpackjs.com/guides/development/#%E4%BD%BF%E7%94%A8-webpack-dev-middleware

  • 定制自己的server,开启服务。
    npm install --save-dev express webpack-dev-middleware
25. HMR 模块热替换功能使用

官网配置:
https://www.webpackjs.com/guides/hot-module-replacement/#%E5%90%AF%E7%94%A8-hmr

  • 没有使用watch模式,也没有使用webpack-dev-middleware的前提下:
  • 浏览器只需要改变当前局部发生改变的组件进行更新展现,不影响其他的模块。
  • 如何配置:
  1. 在webpack。config.js中进行配置:
module.exports = {
  target:'web',  // 屏蔽.browserslistrc的设置
  devServer: {
    hot: true
  },
  }

index.js

+ if (module.hot) {
+   module.hot.accept('./index.js', function() {
+     console.log('Accepting the updated printMe module!');
+     printMe();
+   })
+ }
  • 重启服务
26.React 组件支持热更新

思路:

  1. 需要babel-loader解析jsx语法
  2. hmr
  • npm install @babel/preset-react - D
  • npm install @pmmmwh/react-refresh-webpack-plugin react-refresh -D
  • npm install @babel/core @babel/preset-env @babel-loader- D
  • npm install react-dom react -D
    配置:

babel.config.js

module.exports = {
  presets: [
    ['@babel/preset-env'],
    ['@babel/preset-react'],
  ],
  plugins: [
    ['react-refresh/babel']
  ]
}

webpack.config.js

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

module.exports = {
	target:'web',  // 屏蔽.browserslistrc的设置
	devServer: {
	  hot: true
	 },
	},
	module: {
    rules: [
      {
        test: /\.jsx?$/, // js也会走这条规则
        use: ['babel-loader']
      }
    ],
   plugins: [
   	new ReactRefreshWebpackPlugin()
  ]
}

index.js

import './title'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App.jsx'

if (module.hot) {
  module.hot.accept(['./title.js'], () => {
    console.log('title.js模块更新')
  })
}

ReactDOM.render(<App />, document.getElementById('app'))

package.json

"scripts": {
    "serve": "webpack serve"
  },
27. Vue 组件支持热更新

npm install vue-template-compiler -D
npm install vue-loader -D //

index.js

import Vue from 'vue'
import App from './App.vue'

new Vue({
  render: h => h(App)
}).$mount('#root')

webpack.config.js

const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
	target:'web',  // 屏蔽.browserslistrc的设置
	devServer: {
	  hot: true
	 },
	},
	module: {
    rules: [
      {
        test: /\.vue$/, // js也会走这条规则
        use: ['vue-loader']
      }
    ],
    },
    plugins: [
   	new VueLoaderPlugin()
  ]
}
28. output 中的 path

https://www.webpackjs.com/configuration/output/#output-publicpath

 output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, 'dist'),// 打包资源的输出路径
    //
    publicPath: '/'
  },
  target: 'web',
  devServer: {
    hot: true,
    // 
    publicPath: '/',
    contentBase: path.resolve(__dirname, 'public'),
    watchContentBase: true
  },
/**
 * output
- publicPath:index.html内部的引用路径
- 域名+ publicPath + filename

devServer
- publicPath: 指定本地服务所在的目录
- contentBase: 我们打包之后的资源如果说依赖其它的资源,此时就告知去哪找。
- watchContentBase: true 
 */
30.devServer 常用配置

https://www.webpackjs.com/configuration/dev-server/#devserver

webpack.config.js

devServer: {
    hot: true, // 启用 webpack 的模块热替换特性:
    hotOnly: true, // 启用热模块替换(参见devServer.hot),在构建失败时不刷新页面作为回退。
    port: 4000,
    open: false,
    compress: true, // 一切服务都启用gzip 压缩
    historyApiFallback: true
  },
31proxy 代理设置
  • 为什么会出现跨域?
    在开发阶段,浏览器中访问的是localhost:3000,服务器的访问地址是api.com:4000,就会出现跨域,
    前端在一个服务上,后端在一个服务上。服务器和服务器之间的通信是不会跨域的。
    /api:表示要唤起这个代理。
    我们接口请求的地址是:localhost:3000/api/user。但是我们设置了proxy的target:‘https://api/github.com’。因此我们接口请求的地址就被代理成了’https://api/github.com/api/user`/ 。 target表示问哪个服务端要数据。

在这里插入图片描述

32. resolve 模块解析规则
  • resolve: 配置模块如何被解析。
  • 在webpack中解析的路径分为3类?
    然后每一类按照自己的解析规则去处理。
  1. 相对路径。 例如在项目:import ‘’./title’ 。 根据相对目录来查找文件
  2. 绝对路径。找不到,不做特殊处理。
  3. 模块名称。例如:import React from ‘react’ 根据模块的名称到node_modules中查找。
  • 首先处理好路径,当路径确定了之后确定最后是文件,还是文件夹,如果有后缀,直接根据后缀名称找到对应的文件。
  • 如果是文件用resolve.extensions 处理。
  • 如果是文件夹,用resolve.mainFiles处理文件。
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'], 
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  }
}

在项目中引入组件;import About from ‘./components/Home’
可以修改为:import About from ‘@/components/Home’

33.source-map 作用

mode:告知 webpack 使用相应模式的内置优化。 https://www.webpackjs.com/concepts/mode/#%E7%94%A8%E6%B3%95

devtool: https://www.webpackjs.com/configuration/devtool/#devtool

  • source-map: 是一种技术,一种映射的技术。这个映射指的就是可以去依据我们转换之后的代码,然后再去返还成我们没有转换之前的源代码,之后我们在调试的过程中就可以直接去定位错误在源代码中的信息。
  • 好处: 在调试时可以定位到源代码中的信息。
34.devtool 详细说明
35. ts-loader 编译 TS

npm install --save-dev ts-loader
webpack.config.js

module.exports = {
  module: {
    rules: [
      { test: /\.ts$/, use: 'ts-loader' }
    ]
  }
};
36. babel-loader 编译 TS
  • ts-loader:把我们写的ts语法转换成js语法,但是并不能把polyfill进行填充。
  • 如果使用了新的语法特性ts-loader就能打包,但是不能进行填充和解析,因此就要用到lalbel-loader。例如:promise,async
  • 如何用babel-loader在ts文件中对我们的ts文件进行编译和打包的操作。

babel.config.js

module.exports = {
  presets: [
    ['@babel/preset-env', {
      useBuiltIns: 'usage',
      corejs: 3
    }],
    ['@babel/preset-typescript']
  ]
}
38.区分打包环境
  • webpack-merge 2个对象的合并操作
    目录结构
    在这里插入图片描述
    webpack.common.js
const resolveApp = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { merge } = require('webpack-merge')

// 导入其它的配置
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')

// 定义对象保存 base 配置信息
const commonConfig = {
  entry: './src/index.js',  // 反而没有报错( 相对路径 )
  resolve: {
    extensions: [".js", ".json", '.ts', '.jsx', '.vue'],
    alias: {
      '@': resolveApp('./src')
    }
  },
  output: {
    filename: 'js/main.js',
    path: resolveApp('./dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: 'asset',
        generator: {
          filename: "img/[name].[hash:4][ext]"
        },
        parser: {
          dataUrlCondition: {
            maxSize: 30 * 1024
          }
        }
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: 'asset/resource',
        generator: {
          filename: 'font/[name].[hash:3][ext]'
        }
      },
      {
        test: /\.jsx?$/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'copyWebpackPlugin',
      template: './public/index.html'
    })
  ]
}

module.exports = (env) => {
  const isProduction = env.production

  process.env.NODE_ENV = isProduction ? 'production' : 'development'

  // 依据当前的打包模式来合并配置
  const config = isProduction ? prodConfig : devConfig

  const mergeConfig = merge(commonConfig, config)

  return mergeConfig
}

webpack.prod.js

const CopyWebpackPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  mode: 'production',
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          globOptions: {
            ignore: ['**/index.html']
          }
        }
      ]
    })
  ]
}

webpack.dev.js

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')

module.exports = {
  mode: 'development',
  devtool: 'cheap-module-source-map',
  target: 'web',
  devServer: {
    hot: true,
    hotOnly: true,
    port: 4000,
    open: false,
    compress: true,
    historyApiFallback: true,
    proxy: {
      '/api': {
        target: 'https://api.github.com',
        pathRewrite: { "^/api": "" },
        changeOrigin: true
      }
    }
  },
  plugins: [
    new ReactRefreshWebpackPlugin()
  ]
}

paths.js

const path = require('path')
// 当前应用的根路径
const appDir = process.cwd()
// relativePath: 相对路径
const resolveApp = (relativePath) => {
  return path.resolve(appDir, relativePath)
}

module.exports = resolveApp

package.json

{
  "name": "02_webpack_config_start",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "serve": "webpack serve",
    "build2": "webpack --config ./config/webpack.common.js --env production",
    "serve2": "webpack serve --config ./config/webpack.common.js --env development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.14.8",
    "@babel/core": "^7.15.0",
    "@babel/plugin-transform-arrow-functions": "^7.14.5",
    "@babel/plugin-transform-block-scoping": "^7.14.5",
    "@babel/preset-env": "^7.15.0",
    "@babel/preset-react": "^7.14.5",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
    "autoprefixer": "^10.3.1",
    "axios": "^0.21.1",
    "babel-loader": "^8.2.2",
    "clean-webpack-plugin": "^4.0.0-alpha.0",
    "copy-webpack-plugin": "^9.0.1",
    "css-loader": "^6.2.0",
    "html-webpack-plugin": "^5.3.2",
    "less": "^4.1.1",
    "less-loader": "^10.0.1",
    "postcss": "^8.3.6",
    "postcss-cli": "^8.3.1",
    "postcss-loader": "^6.1.1",
    "postcss-preset-env": "^6.7.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-refresh": "^0.10.0",
    "react-router-dom": "^5.2.0",
    "style-loader": "^3.2.1",
    "webpack": "^5.47.1",
    "webpack-cli": "^4.7.2",
    "webpack-dev-server": "^3.11.2",
    "webpack-merge": "^5.8.0"
  },
  "dependencies": {
    "core-js": "^3.16.0",
    "express": "^4.17.1",
    "regenerator-runtime": "^0.13.9",
    "webpack-dev-middleware": "^5.0.0"
  }
}


babel.config.js

const presets = [
  ['@babel/preset-env'],
  ['@babel/preset-react'],
]

const plugins = []

console.log(process.env.NODE_ENV, '<------')

// 依据当前的打包模式来决定plugins 的值 
const isProduction = process.env.NODE_ENV === 'production'
if (!isProduction) {
  plugins.push(['react-refresh/babel'])
}

module.exports = {
  presets,
  plugins
}

postcss.config.js

module.exports = {
  plugins: [
    require('postcss-preset-env')
  ]
}

.browserslistrc

> 1% 
last 2 version
not dead
42.代码拆分方式

代码分离:https://webpack.docschina.org/guides/code-splitting/

  • 为什么在webpack.进行打包的时候如何对代码块进行打包输出的操作。会分2个步骤进行描述,
  1. 为什么由一个入口找到所有依赖再去打包到一个bundle中不合适?
  2. 在webpack中具体有哪几种方式可以帮助我们实现拆分打包的需求?

在首屏加载中,
代码的分离打包3种方式:
1. 第一种多入口的打包方式
修改webpack.common.js文件

entry: {
    main1: './src/main1.js',
    main2: './src/main2.js'
    },
output: {
    filename: 'js/[name].build.js',
    path: resolveApp('./dist')
  },
    
  1. 入口添加依赖 TerserWebpackPlugin
    webpack.common.js
    https://webpack.docschina.org/configuration/optimization/#optimizationminimizer
const TerserPlugin = require("terser-webpack-plugin");

const commonConfig = {
	entry: {
		//	dependOn: 依赖的包
	    main1: { import: './src/main1.js', dependOn: 'shared' },
    	main2: { import: './src/main2.js', dependOn: 'shared' },
    	shared: ['lodash', 'jquery']
	  },
	optimization: {
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ],
  },
}
  1. splitChunks
    官方讲解splitChunks配置参数:https://webpack.docschina.org/configuration/optimization/#optimizationsplitchunks

webpack.common.js

const commonConfig = {
	entry: {
    index: './src/index.js'
  },
	optimization: {
    splitChunks: {
      chunks: 'all' // async :处理异步导入。 all:不论是异步或者同步都可以处理。 默认:异步处理方式。initial:同步导入
    }
  },
}
  • 以上最常见的方式是第3种
42splitChunks配置

splitChunks打包出来的文件命名方式有4种

  • 1.xxx.bundle.js
  • 2.xxx.venderos.js
  • 3.xxxchunk.js
  • 4.runtime.js
 + splitChunks: {
      chunks: 'initial', // async initial all
      minSize: 20000, // 如果包的大小达不到20000(20kb默认值),就不会进行分包处理
      maxSize: 20000, // 默认值 0 。体积大于maxSize的值的包进行拆分,拆分的规则:是拆分出来的包的大小不能小于minSize值的大小。如果用默认值会有警告,一般设置和minSize一样。
      minChunks: 1, // 我们的包如果要被拆分,至少被引用一次。minChunks的值如果大于1,:minSize和maxSize最好不要再设置了。会影响打包的结果。
      cacheGroups: { // 对拆分的过程进行分组
        syVendors: {
          test: /[\\/]node_modules[\\/]/,
          filename: 'js/[id]_vendor.js',
          priority: -10,  // 优先级的属性
        },
        default: {
          minChunks: 1,
          filename: 'js/syy_[id].js',
          priority: -20,
        }
      }
    }
43.import 动态导入配置

如何用动态导入的方式对我们的代码进行拆包的操作。
chunkIds:
在这里插入图片描述

output: {
    filename: 'js/[name].bundle.js',
    path: resolveApp('./dist'),
+ chunkFilename: 'js/chunk_[name].js'
  },
  optimization: {
    // 当前文件的名称是按自然数进行编号排序,如果某个文件当前次不再被依赖那么重新打包时序号都会变
    // 文件打包出来的命名规则。
 +  chunkIds: 'deterministic', // 'natural','named' // 开发阶段设置为:named。生产阶段:deterministic
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ]
  },

魔法注释语法:

// import ('./title') 改成下面的引入方法
+ import(/*webpackChunkName: "title"*/'./title')
44. runtimeChunk 优化配置

runtimeChunk:官方文档:https://webpack.docschina.org/configuration/optimization/#optimizationsplitchunks

output: {
   - filename: 'js/[name].bundle.js',
   + filename: 'js/[name].[contenthash:8].bundle.js',
    path: resolveApp('./dist'),
  },
  optimization: {
   +     runtimeChunk: true, // false, single:a文件用到了c,b文件也用到了c,如果设置为true,那么都会打包出来一个c,如果设置了single,那就会只打包出来一个c 
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ]
  },
45.代码懒加载
  • 基于动态导入的方式实现懒加载
  • 按需加载:场景案例:首评页面只有点击某个按钮,才会加载这个js文件,如果没有点击不需要加载这个js文件。
// 这样在文件中导入,用不用都会加载。
// import ('./utils')
const oBtn = document.createElement('button')
oBtn.innerHTML = '点击加载元素'
document.body.appendChild(oBtn)

// 按需加载
oBtn.addEventListener('click', () => {
// 只有点击这个按钮才会加载这个文件。
+ import('./utils').then(({ default: element }) => {
    console.log(element)
    document.body.appendChild(element)
  })
})
46. prefetch 与 preload

官方描述:https://webpack.docschina.org/guides/code-splitting/#prefetchingpreloading-modules
在用户没有感知到情况下对将来可能要用到的文件进行加载。
用法:

const oBtn = document.createElement('button')
oBtn.innerHTML = '点击加载元素'
document.body.appendChild(oBtn)

// 按需加载
oBtn.addEventListener('click', () => {
  import(
    /*webpackChunkName:'utils' */
+   /*webpackPreLoad:true */
    './utils').then(({ default: element }) => {
      console.log(element)
      document.body.appendChild(element)
    })
})
  • preload与 prefetch 指令相比,preload 指令有许多不同之处:
  1. preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
  2. preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
  3. preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。
  4. 浏览器支持程度不同。
47.第三方扩展设置 CDN
  • 开发过程中为什么使用到cdn?cdn是什么?
    cdn是一个内容分发网络,是一个整个的体系。有了这个cdn网络,可以让用户在请求资源的时候,首先以最快的速度找到离他最近的资源服务器,然后取回他想要的内容。这样的话我们就可以把用户想要的东西更快的发给他。体验高性能,扩展性强。
    在这里插入图片描述
    用户1 查找资源,服务器会从离他最近的地方开始查找,如果没有就去旁边的边缘节点查找,如果边缘节点也没有,就去父节点,父节点没有就去源节点,源节点如果有就拷贝一份到父节点,父节点-- >拷贝一份到边缘节点,最后返回给用户1。

  • 在实际的开发中怎么去用cdn?
    结合webpack用。如果我们自己有cdn服务器,那么我们完全可以把打包完的代码直接部署在cdn服务器上。cdn服务器要买,价格不一。开发阶段用免费别人放在服务器上的资源的就好了。

例如代码中用到了lodash库。

代码配置:

// 抽离第3方包依赖,不进行打包。
  externals: {
    lodash: '_' // _:表示对全局变量暴漏的包名,不能乱写。
  },

在模版中进行引入cdn地址:
index.html

<!DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">

  <title>
    <%= htmlWebpackPlugin.options.title %>
  </title>
</head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
        Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
 +  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
  <!-- built files will be auto injected -->
</body>

</html>

对cdn进行一些设置,从而对我们的项目做一些优化:

48.打包 Dll 库
  • 如何使用 Dll 库对我们构建过程进行优化。
    官方描述:https://webpack.docschina.org/plugins/dll-plugin/#dllplugin

  • DllPlugin 和 DllReferencePlugin 用某种方法实现了拆分 bundles,同时还大幅度提升了构建的速度。“DLL” 一词代表微软最初引入的动态链接库。

  • 案例:在react开发过程中:不想每次react库和raect-dom库都跟着入口文件一块打包,提前做成一个dll库,用到的时候直接找dll动态库就可以了。和cdn的思想类似。会生成2个文件分别是:dll_react.js,react.manifest.json。将来用的时候用.json文件,.json文件会找到.js的源文件。

  • 提高打包的构建速度。
    dll/webpack.config.js

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({
        extractComments: false
      }),
    ],
  },
  plugins: [
    new webpack.DllPlugin({
      // 生成的dll包名
      name: 'dll_[name]',
      // 记录路径信息:manifest.json 文件的 绝对路径(输出文件)
      path: path.resolve(__dirname, './dll/[name].manifest.json')
    })
  ]
}

package.json

{
  "name": "dll",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "dll": "webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "webpack": "^5.52.0",
    "webpack-dev": "^1.1.1"
  }
}

  • 执行命令npm run dll
  • 生成如下文件:
    在这里插入图片描述
49.使用 Dll 库

webpack.common.js

const webpack = require('webpack')
// 只使用DllReferencePlugin,发现不能对模版文件进行填充。
// 对模版文件进行动态填充
+ const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
plugins: [
+    new webpack.DllReferencePlugin({
      // context: 查找动态乱接库 .js文件
+     context: resolveApp('./'),
      // manifest: 去哪个地方找文件的名称
+    manifest: resolveApp('./dll/dll/react.manifest.json')
+ }),
+    new AddAssetHtmlPlugin({
// 在打包出来的文件index.html中引用js的文件。如果设置为auto,着则不需要手动修改,如果使用js,则需要手动修改index.html引入的路径
+     outputPath: 'auto', // 'auto', 'js'
+   filepath: resolveApp('./dll/dll/dll_react.js')
+ })
  ]

打包出来的件index.html

<!doctype html>
<html lang="">
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width,initial-scale=1">
		<title>
			copyWebpackPlugin
		</title>
+       
+ <script defer="defer" src="auto/dll_react.js">
		</script>
		<script defer="defer" src="js/runtime~index.bundle.js">
		</script>
		<script defer="defer" src="js/index.bundle.js">
		</script>
	</head>
	<body>
		<noscript>
			<strong>
				We're sorry but copyWebpackPlugin doesn't work properly without JavaScript
				enabled. Please enable it to continue.
			</strong>
		</noscript>
		<div id="app">
		</div>
		<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js">
		</script>
	</body>

</html>
  • 如果每次都把react,react-dom都打包进去,那么对于时间消耗是非常大的。因此,我们想着把这些单独的抽离出来,做成一个独立的库文件,之后在其他的地方用到,我们就可以找这个文件进行使用。类似于cdn。我们在打包的时候,不需要进行单独的打包了。这就是为什么使用dll库。
  • 现在react,vue已经移除了对dll的使用。
50 . CSS 抽离和压缩

抽离css为一个单独的文件,而不是在当前的文件的<style></style>里面

配置:
webpack.config.js

// css文件抽离
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

+ const commonConfig = (isProduction) => {
 +return {
	rules: [
      {
        test: /\.css$/,
        use: [
+          isProduction ? MiniCssExtractPlugin.loader :'style-loader' ,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              esModule: false
            }
          },
          'postcss-loader'
        ]
      },
      ]
   }
 }
module.exports = (env) => {
  const isProduction = env.production

  process.env.NODE_ENV = isProduction ? 'production' : 'development'

  // 依据当前的打包模式来合并配置
  const config = isProduction ? prodConfig : devConfig

 + const mergeConfig = merge(commonConfig(isProduction), config)

  return mergeConfig
}

webpack.prod.js

// css抽离出来的文件压缩
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
  optimization: {
    minimizer: [
      new CssMinimizerPlugin(),
    ]
  },

在这里插入图片描述
在这里插入图片描述

51. TerserPlugin 压缩 JS

压缩js文件:TerserWebpackPlugin: 官方描述: https://webpack.docschina.org/plugins/terser-webpack-plugin/
效果:
源码:
使用TerserPlugin

底层就是使用terser这个库。

如果是webpack5不需要安装,如果是webpack4需要安装。

52. scope hoisting(作用域的提升)
53. usedExports 配置

性能提升。tree shaking(树摇:去除死代码)

  • 1.tree shaking是什么?帮助我们解决了什么问题?
  • 在一个文件中如果没有使用这个函数,那么不希望被打包进去,因此可以减少打包的体格和速度。极少成多,如果代码中很多这样的场景,那么整个性能也就得到了提升。
  • 树摇:摇掉死(不用的)代码。
  • 树摇: 核心原理:基于esmodule的静态语法分析,就像是可以通过一个人对代码进行扫描,标记出未被使用的代码,在后期打包的时候去掉,不参与打包。只能对esmodule格式的代码起作用。
  • 2.在webpack中这针对tree shaking有什么样的实现方式?在webpack中有2种方式实现。1.usedExports。2.sideEffects
  • 3.不同的实现方式具体的配置是怎么样的?
  1. usedExports配置:https://webpack.docschina.org/configuration/optimization/#optimizationusedexports
  • usedExports 只是标记不被使用的函数,如果把标记的没用的代码去掉还要结合TerserPlugin一块使用。
  • TerserPlugin:根据标记,摇掉没使用的代码。
  • webpack.prod.js
    usedExports配合TerserPlugin一块使用
module.exports = {
  mode: 'development',
  devtool: false,
  optimization: {
  // 只是标记不被使用的函数
+   usedExports: true,
+   minimize: true, // 必须开启,否则没办法摇掉。
+   minimizer: [
+      new TerserPlugin({
        extractComments: false,
      }),
    ]
  },
}

在这里插入图片描述

  1. sideEffects (副作用)配置
{
  "name": "awesome npm module",
  "version": "1.0.0",
  "sideEffects": true, // true:开启,false:不开启。[./src]:具体的文件
}

在某些导入的函数中可能是不被使用的,那么可以通过usedExports进行标记,通过TerserPlugin进行清除 但是这种情况并不能满足所有树摇的场景,例如:我们在react中编写代码的时候写了一些带有副作用的代码, 但是在打包的时候想清除掉,那么怎么办呢?我们可以通过sideEffects进行配置,在package.json中进行 添加就行了,最简单粗暴的就是:"sideEffects": false,所有模块的副作用都不要,但是有些文件的副作用是需要 保留的,那么怎么办呢?例如css文件,那么我们可以给sideEffects一个数组,通过数组指定不跳过哪些文件。针对 css我们给了一个单独的处理,直接在rules里面添加"sideEffects": true。

55.Css-TreeShaking

对css代码进行TreeShaking(删除不用的css )

webpack.prod.js

const PurgeCSSPlugin = require('purgecss-webpack-plugin')
const glob = require('glob')
plugins:[
new PurgeCSSPlugin({
		// paths:路径
      paths: glob.sync(`${resolveApp('./src')}/**/*`, { nodir: true }),
      // safelist:安全列表。不会把'body', 'html', 'ef'剔除
      safelist: function () {
        return {
          standard: ['body', 'html', 'ef']
        }
      }
    })
]
56.资源压缩 - gzip

生产环境压缩:
http压缩:网络消耗带宽变小。从而节省性能。
CompressionWebpackPlugin: https://webpack.docschina.org/plugins/compression-webpack-plugin/

  • http的压缩流程分几步?

webpack.prod.js

const CompressionPlugin = require("compression-webpack-plugin");
plugins: [
new CompressionPlugin({
      test: /\.(css|js)$/, // 只压缩js/css文件,
      minRatio: 0.8, // 最小压缩比例
      threshold: 0,
      algorithm: 'gzip' // 压缩的方式
    })
],
  • 经过这个压缩的可以部署在服务端。
57. inlineChunkHtmlPlugin 使用

webpack.prod.js

var HtmlWebpackPlugin = require('html-webpack-plugin');
var InlineChunkHtmlPlugin = require('inline-chunk-html-plugin');
plugins: [
	new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime.*\.js/])
]
58. webpack 打包 Library
59. 打包时间和内容分析
  1. 打包时间分析:SpeedMeasurePlugin: https://www.npmjs.com/package/speed-measure-webpack-plugin

webpack.common.js

// 时间分析
+ const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
+ const smp = new SpeedMeasurePlugin()

module.exports = (env) => {
 + return smp.wrap(mergeConfig)
}

package.json

 "mini-css-extract-plugin": "^1.3.6",

打包时间:

在这里插入图片描述

  1. BundleAnalyzerPlugin: 官方描述: https://webpack.docschina.org/guides/code-splitting/#bundle-analysis
  • webpack-bundle-analyzer:

webpack.prod.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
plugins:[
	new BundleAnalyzerPlugin()
]

直接npm run build之后,会在默认的端口开启一个服务,自己打开一个浏览器窗口。

  • 帮助我们定位性能消耗在了哪?知道了消耗在哪之后,具体的采用方式来解决。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值