webpack 学习入门

webpack

    • 1. 简介
      • 1.1 webpack 是什么
      • 1.2 webpack 五个核心概念
        • 1.2.1 入口 - Entry
        • 1.2.2 出口 - Output
        • 1.2.3 Loader
        • 1.2.4 插件 - Plugins
        • 1.2.6 模式 - Mode
    • 2. webpack 初体验
      • 2.1 初始化配置
        • 2.1.1. 准备
        • 2.1.2. 写代码
        • 2.1.3 编译打包应用
    • 3. webpack 开发环境的基本配置
      • 3.1 打包样式资源
      • 3.2 打包 HTML 资源
      • 3.3 打包图片资源
      • 3.4 打包其他资源
      • 3.5 开发环境配置 - devServer
      • 总结
    • 4. webpack 生产环境的基本配置
      • 4.1 提取 css 成单独文件
      • 4.2 css 兼容性处理
      • 4.3 压缩 css
      • 4.4 js语法检查
      • 4.5 js 兼容性处理
      • 4.6 js 压缩
      • 4.7 HTML 压缩
      • 4.8 生产环境配置
    • 5. webpack 优化配置
      • 5.1 开发环境性能优化
        • 5.1.1 优化打包构建速度
          • HMR
        • 5.1.2 优化代码调试
          • source-map
      • 5.2 生产环境性能优化
        • 5.2.1 优化打包构建速度
          • oneOf
          • babel缓存
          • 多进程打包
          • externals
          • dll
        • 5.2.2 优化代码运行的性能
          • 缓存(hash-chunkhash-contenthash)
          • tree shaking
          • code split
          • 懒加载/预加载
          • PWA(渐进式 Web 应用)配置详解

在这里插入图片描述

1. 简介

1.1 webpack 是什么

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。
在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。
它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。
在这里插入图片描述

1.2 webpack 五个核心概念

  • entry:入口,指示打包的起点文件
  • output:输出,指示打包资源bundles输出路径和命名
  • loader:处理非js文件(webpack自身只理解js、json),相当于翻译官
  • plugins:功能插件,可以做到优化、压缩、定义环境变量等
  • mode:模式分为 development和production 模式
1.2.1 入口 - Entry

入口(Entry)是 webpack 分析构建内部依赖图的起点模块(模块就是一个文件)。

// webpack.config.js:
module.exports = {entry: './path/to/my/entry/file.js'
};
1.2.2 出口 - Output

output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist

/*webpack.config.js  webpack的配置文件作用: 指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置)所有构建工具都是基于nodejs平台运行的~模块化默认采用commonjs。
*/
const path = require('path');
module.exports = {entry: './path/to/my/entry/file.js',output: {// 输出路径://    --dirname: nodeJs的变量,代表当前文件的绝对路径//    resolve: nodeJs里path模块的方法,用来拼接绝对路径path: path.resolve(__dirname, 'dist'),// 输出文件名filename: 'my-first-webpack.bundle.js'}
};
1.2.3 Loader

loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解JavaScript);
loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块。

loader的使用:

  • 需要先下载;
  • 无需requrie
// webpack.config.js:
const { resolve } = require('path');
const config = {output: {filename: 'my-first-webpack.bundle.js',path: resolve(__dirname, 'dist')},module: {rules: [// 不同类型的文件必须配置不同的规则来处理{test: /\.css$/, // 匹配什么样的文件// use数组中loader的执行顺序:从下到上,从右到左(后进先出)use: ['style-loader', 'css-loader' ]}]}
};
module.exports = config;
1.2.4 插件 - Plugins

插件(Plugins)可以用于执行范围更广(比loader)的任务。插件的范围包括:从打包优化和压缩,一直到重新定义环境中的变量等。

plugin的使用:

  • 需要先下载;
  • 还需requrie
// webpack.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const config = {module: {rules: [{ test: /\.txt$/, use: 'raw-loader' }]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})]
};
module.exports = config;
1.2.6 模式 - Mode

模式(Mode)指示 webpack 使用相应模式的配置;

  • mode分为 ‘development’ 和 ‘production’;
  • 生产环境和开发环境将 ES6 模块化编译成浏览其能识别的模块化;
  • 生产环境比开发环境多一个压缩js代码;
选项描述特点
development会将DefinePluginprocess.env.NODE_ENV的值设置为development。启用NamedChunksPluginNamedModulesPlugin能让代码本地调试运行的环境
production会将DefinePluginprocess.env.NODE_ENV的值设置为production。启用FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin能让代码优化上线运行的环境
// webpack.config.js:
module.exports = {mode: 'production'
};

2. webpack 初体验

2.1 初始化配置

2.1.1. 准备
  • 初始化 package.json
  • 下载并安装 webpack
 //初始化 package.json
npm init
//下载并安装 webpack
npm i webpack webpack-cli -D
// 也下载loader和 plugins
npm i xxx-loader xxx-plugin -D
2.1.2. 写代码

需要在项目的根目录写一个名为webpack.config.js的配置文件。

webpack初体验
├── src
│   └── index.js
│   └── test.json
├── webpack.config.js
├── package.json

代码

// 1. src/index.js
import data from './test.json';
console.log(data);
function add(x, y) {return x + y;
}
add(1, 2)
console.log(add(1, 2))// 2. src/test.json
{"testJson": "test json"
}// 3. webpack.config.js
const { resolve } = require('path'); // 
module.exports = {entry: './src/index.js',output: {filename: 'built.js',path: resolve(__dirname, 'build')},module: {rules: [{test: /\.css$/,use: ['style-loader','css-loader' ]}]},plugins: [],mode: 'development'
}
2.1.3 编译打包应用

package.json 中添加 脚本命令"dev": "SET NODE_OPTIONS=--openssl-legacy-provider & webpack"

//package.json
{"name": "webpack_test","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev": "SET NODE_OPTIONS=--openssl-legacy-provider & webpack"},"author": "","license": "ISC","devDependencies": {"css-loader": "^5.0.0","style-loader": "^2.0.0","webpack": "^4.41.6","webpack-cli": "^3.3.11"}
}
# 打包执行
npm run dev

在这里插入图片描述

3. webpack 开发环境的基本配置

3.1 打包样式资源

  1. 创建文件
    在这里插入图片描述
  2. 下载安装 loader 包
npm i css-loader style-loader less-loader less -D
  1. 修改配置文件
/*webpack.config.js  webpack的配置文件作用: 指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置)所有构建工具都是基于nodejs平台运行的~模块化默认采用commonjs。
*/// resolve用来拼接绝对路径的方法
const { resolve } = require('path');module.exports = {// webpack配置// 入口起点entry: './src/index.js',// 输出output: {// 输出文件名filename: 'built.js',// 输出路径// __dirname nodejs的变量,代表当前文件的目录绝对路径path: resolve(__dirname, 'build')},// loader的配置module: {rules: [// 详细loader配置// 不同文件必须配置不同loader处理{// 匹配哪些文件test: /\.css$/,// 使用哪些loader进行处理use: [// use数组中loader执行顺序:从右到左,从下到上 依次执行// 创建style标签,将js中的样式资源插入进行,添加到head中生效'style-loader',// 将css文件变成commonjs模块加载js中,里面内容是样式字符串(转换后得到的commonjs模块可以理解为:用js给元素动态添加样式的那种代码);'css-loader']},{test: /\.less$/,use: ['style-loader','css-loader',// 将less文件编译成css文件// 需要下载 less-loader和less'less-loader']}]},// plugins的配置plugins: [// 详细plugins的配置],// 模式mode: 'development', // 开发模式// mode: 'production'
}
  1. 运行指令: webpack

3.2 打包 HTML 资源

  1. 创建文件
    在这里插入图片描述

  2. 下载安装 plugin 包

npm install --save-dev html-webpack-plugin
  1. 修改配置文件
/*loader: 1. 下载   2. 使用(配置loader)plugins: 1. 下载  2. 引入  3. 使用
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/index.js',output: {filename: 'built.js',path: resolve(__dirname, 'build')},module: {rules: [// loader的配置]},plugins: [// plugins的配置// html-webpack-plugin// 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)// 需求:需要有结构的HTML文件/*** html-webpack-plugin*    1) 不传参的情况 - new HTMLWebpackPlugin():会在配置的output文件夹创建一个空的html, 自动引入打包输出的所有资源,包括js, css...*    2) 参数template:复制设置的'./src/index.html'文件到配置的output文件夹,并自动引入打包输出的所有资源*/new HtmlWebpackPlugin({// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)template: './src/index.html'})],mode: 'development'
};
  1. 运行指令: webpack

3.3 打包图片资源

  1. 创建文件
    在这里插入图片描述

  2. 下载安装 loader 包

npm install --save-dev html-loader url-loader file-loader
  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/index.js',output: {filename: 'built.js',path: resolve(__dirname, 'build')},module: {rules: [{test: /\.less$/,// 要使用多个loader处理用useuse: ['style-loader', 'css-loader', 'less-loader']},{// 问题:默认处理不了html中img图片// 处理图片资源test: /\.(jpg|png|gif)$/,// 使用一个loader// 下载 url-loader file-loaderloader: 'url-loader',options: {// 图片大小小于8kb,就会被base64处理// 优点: 减少请求数量(减轻服务器压力)// 缺点:图片体积会更大(文件请求速度更慢)limit: 8 * 1024,// 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs// 解析时会出问题:[object Module]// 解决:关闭url-loader的es6模块化,使用commonjs解析esModule: false,// 给图片进行重命名// [hash:10]取图片的hash的前10位// [ext]取文件原来扩展名name: '[hash:10].[ext]'}},{test: /\.html$/,// 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)loader: 'html-loader'}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})],mode: 'development'
};
  1. 运行指令: webpack

3.4 打包其他资源

  1. 创建文件
    在这里插入图片描述

  2. 下载安装 loader 包

npm install --save-dev html-loader url-loader file-loader
  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/index.js',output: {filename: 'built.js',path: resolve(__dirname, 'build')},module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader']},// 打包其他资源(除了html/js/css资源以外的资源,比如字体文件等){// 排除css/js/html资源exclude: /\.(css|js|html|less)$/,loader: 'file-loader',options: {name: '[hash:10].[ext]'}}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})],mode: 'development'
};
  1. 运行指令: webpack

3.5 开发环境配置 - devServer

  • devServer:开发服务器,用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
  • 特点:只会在内存中编译打包,不会有任何输出(不会在项目中新建一个文件夹)
  1. 创建文件
    在这里插入图片描述

  2. 修改配置文件

/*开发环境配置:能让代码运行运行项目指令:webpack 会将打包结果输出出去npx webpack-dev-server 只会在内存中编译打包,没有输出
*/const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/js/index.js',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'),// 启动gzip压缩compress: true,// 端口号port: 3000,// 自动打开浏览器open: true}
};
  1. 运行指令:
npx webpack-dev-server

总结

  1. 打包样式资源:
    • 安装 css-loader, style-loader, less-loader, less
    • 配置 webpack.config.js 来处理 .css 和 .less 文件。
  2. 打包 HTML 资源:
    • 安装 html-webpack-plugin
    • 使用 HtmlWebpackPlugin 自动生成包含 JS/CSS 的 HTML 文件。
  3. 打包图片资源:
    • 安装 url-loader, file-loader, html-loader
    • 配置 url-loader 处理图片资源,支持 base64 编码。
  4. 打包其他资源:
    • 使用 file-loader 处理非 CSS/JS/HTML 资源。
  5. 开发环境配置:
    • 配置 devServer 自动编译、自动打开浏览器并实时刷新。
    • 设置 contentBase, compress, port, open 等选项。

4. webpack 生产环境的基本配置

4.1 提取 css 成单独文件

  1. 下载安装包
    在这里插入图片描述

  2. 下载插件

npm install --save-dev mini-css-extract-plugin
  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},module: {rules: [{test: /\.css$/,use: [// 创建style标签,将样式放入// 'style-loader', // 这个loader取代style-loader。作用:提取js中的css成单独文件MiniCssExtractPlugin.loader,// 将css文件整合到js文件中'css-loader']}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'}),new MiniCssExtractPlugin({// 对输出的css文件进行重命名filename: 'css/built.css'})],mode: 'development'
};
  1. 运行指令: webpack

4.2 css 兼容性处理

  1. 创建文件
    在这里插入图片描述

  2. 下载 loader

npm install --save-dev postcss-loader postcss-preset-env
  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');// 设置nodejs环境变量
// process.env.NODE_ENV = 'development';module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},module: {rules: [{test: /\.css$/,use: [MiniCssExtractPlugin.loader,'css-loader',/*css兼容性处理:postcss --> postcss-loader postcss-preset-env帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式"browserslist": {// 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development"development": ["last 1 chrome version","last 1 firefox version","last 1 safari version"],// 生产环境:默认是看生产环境"production": [">0.2%","not dead","not op_mini all"]}*/// 使用loader的默认配置// 'postcss-loader',// 修改loader的配置{loader: 'postcss-loader',options: {ident: 'postcss',plugins: () => [// postcss的插件require('postcss-preset-env')()]}}]}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'}),new MiniCssExtractPlugin({filename: 'css/built.css'})],mode: 'development'
};
  1. 修改 package.json
"browserslist": {"development": ["last 1 chrome version","last 1 firefox version","last 1 safari version"],"production": [">0.2%","not dead","not op_mini all"]
}
  1. 运行指令: webpack

4.3 压缩 css

  1. 创建文件
    在这里插入图片描述
  2. 下载安装包
npm install --save-dev optimize-css-assets-webpack-plugin
  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')// 设置nodejs环境变量
// process.env.NODE_ENV = 'development';module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},module: {rules: [{test: /\.css$/,use: [MiniCssExtractPlugin.loader,'css-loader',{loader: 'postcss-loader',options: {ident: 'postcss',plugins: () => [// postcss的插件require('postcss-preset-env')()]}}]}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'}),new MiniCssExtractPlugin({filename: 'css/built.css'}),// 压缩cssnew OptimizeCssAssetsWebpackPlugin()],mode: 'development'
};
  1. 运行指令: webpack

4.4 js语法检查

  1. 创建文件
    在这里插入图片描述
  2. 下载安装包
npm install --save-dev eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import
  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},module: {rules: [/*语法检查: eslint-loader  eslint注意:只检查自己写的源代码,第三方的库是不用检查的设置检查规则:package.json中eslintConfig中设置~"eslintConfig": {"extends": "airbnb-base"}airbnb --> eslint-config-airbnb-base  eslint-plugin-import eslint*/{test: /\.js$/,exclude: /node_modules/,loader: 'eslint-loader',options: {// 自动修复eslint的错误fix: true}}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})],mode: 'development'
};
  1. 配置 package.json
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
}
  1. 运行指令: webpack

4.5 js 兼容性处理

JS兼容性处理
1)什么是JS兼容性处理?
其实就是把ES6及以上(后边简写为ES6+)新增的语法、API处理成ES5及以下的版本,解决某些浏览器(ie)上的兼容性报错问题。
2)Babel简介: Babel
是一个工具链,主要用于在当前和旧的浏览器或环境中,将ES6+代码转换为JavaScript向后兼容版本的代码。
3)polyfill是啥?
⁉️:不知道大家之前有没有过这种疑问:只知道babel是处理ES6+兼容的,polyfill分别是干嘛的😵?
🅰️:其实,ES6+语法和新增的API需要分开进行处理,polyfill是针对新增API的~(比如:箭头函数是新增语法,Promise是新增的API)
4)请大家跟我一起看一段代码(下面JS兼容性处理相关内容将以这个作为例子):

console.log(add(2, 5));// 新API const promise = new Promise(resolve => {   setTimeout(() => {console.log('定时器执行完了~');resolve();   }, 1000); });console.log(promise); 

上面代码如果不做任何兼容性处理,运行结果如下: ie无法识别ES6+的内容
在这里插入图片描述

  1. 下载安装包
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/polyfill core-js
  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},module: {rules: [/*js兼容性处理:babel-loader @babel/core 1. 基本js兼容性处理 --> @babel/preset-env问题:只能转换基本语法,如promise高级语法不能转换2. 全部js兼容性处理 --> @babel/polyfill  问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~3. 需要做兼容性处理的就做:按需加载  --> core-js*/  {test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader',options: {// 预设:指示babel做怎么样的兼容性处理presets: [['@babel/preset-env',{// 按需加载/** https://babeljs.io/docs/en/babel-preset-env#usebuiltins* useBuiltIns:配置@babel/preset-env如何处理polyfills,取“usage”,“entry”,“false”之一,默认为“false”*  - 当使用usage或entry选项时,@babel/preset-env将添加对core-js模块的直接引用,类似import(或require)。这意味着core-js将相对于文件本身进行解析,并且按需引入。*/useBuiltIns: 'usage',// 指定core-js版本corejs: {version: 3},// 指定兼容性做到哪个版本浏览器targets: {chrome: '60',firefox: '60',ie: '9',safari: '10',edge: '17'}}]]}}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})],mode: 'development'
};
  1. 运行指令: webpack

4.6 js 压缩

  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})],// 生产环境下会自动压缩js代码mode: 'production'
};
  1. 运行指令: webpack

4.7 HTML 压缩

  1. 修改配置文件
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},plugins: [new HtmlWebpackPlugin({template: './src/index.html',// 压缩html代码minify: {// 移除空格collapseWhitespace: true,// 移除注释removeComments: true}})],mode: 'production'
};
  1. 运行指令:webpack

4.8 生产环境配置

const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';// 复用loader
const commonCssLoader = [MiniCssExtractPlugin.loader,'css-loader',{// 还需要在package.json中定义browserslistloader: 'postcss-loader',options: {ident: 'postcss',plugins: () => [require('postcss-preset-env')()]}}
];module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},module: {rules: [{test: /\.css$/,use: [...commonCssLoader]},{test: /\.less$/,use: [...commonCssLoader, 'less-loader']},/*正常来讲,一个文件只能被一个loader处理。当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:先执行eslint 在执行babel*/{// 在package.json中eslintConfig --> airbnbtest: /\.js$/,exclude: /node_modules/,// 优先执行enforce: 'pre',loader: 'eslint-loader',options: {fix: true}},{test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader',options: {presets: [['@babel/preset-env',{useBuiltIns: 'usage',corejs: {version: 3},targets: {chrome: '60',firefox: '50'}}]]}},{test: /\.(jpg|png|gif)/,loader: 'url-loader',options: {limit: 8 * 1024,name: '[hash:10].[ext]',outputPath: 'imgs',esModule: false}},{test: /\.html$/,loader: 'html-loader'},{exclude: /\.(js|css|less|html|jpg|png|gif)/,loader: 'file-loader',options: {outputPath: 'media'}}]},plugins: [new MiniCssExtractPlugin({filename: 'css/built.css'}),new OptimizeCssAssetsWebpackPlugin(),new HtmlWebpackPlugin({template: './src/index.html',minify: {collapseWhitespace: true,removeComments: true}})],mode: 'production'
};

5. webpack 优化配置

5.1 开发环境性能优化

5.1.1 优化打包构建速度
HMR

Hot Module Replacement,也称为HMR,是一种在应用程序运行时替换、添加或删除模块的技术,无需完全刷新页面就能更新这些模块。

  • 修改 JS 文件,无需刷新页面,而能够直接在页面进行代码更新。
  • 修改 CSS 文件,无需刷新页面,改动的样式能直接呈现。
  1. 修改配置文件
/*HMR: hot module replacement 热模块替换 / 模块热替换作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块) 极大提升构建速度样式文件:可以使用HMR功能:因为style-loader内部实现了~js文件:默认不能使用HMR功能 --> 需要修改js代码,添加支持HMR功能的代码注意:HMR功能对js的处理,只能处理非入口js文件的其他文件。html文件: 默认不能使用HMR功能.同时会导致问题:html文件不能热更新了~ (不用做HMR功能)解决:修改entry入口,将html文件引入
*/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}
};
  1. 运行指令: webpack
5.1.2 优化代码调试
source-map

Sourcemap 协议最初由 Google 设计并率先在 Closure Inspector
实现,它能够将经过压缩、混淆、合并的代码还原回未打包状态,帮助开发者在生产环境中精确定位问题发生的行列位置。
目前很多第三方库在发布的文件中都会同时提供一个 .map 后缀的 Source Map 文件。例如 jQuery。我们可以打开它的
Source Map 文件看一下,如下图所示:
在这里插入图片描述
这是一个 JSON 格式的文件,为了更容易阅读,我提前对该文件进行了格式化。这个 JSON
里面记录的就是转换后和转换前代码之间的映射关系,主要存在以下几个属性:

  • version 是指定所使用的 Source Map 标准版本;
  • sources 中记录的是转换前的源文件名称,因为有可能出现多个文件打包转换为一个文件的情况,所以这里是一个数组;
  • names 是源代码中使用的一些成员名称,我们都知道一般压缩代码时会将我们开发阶段编写的有意义的变量名替换为一些简短的字符,这个属性中记录的就是原始的名称;
  • mappings 属性,这个属性最为关键,它是一个叫作 base64-VLQ 编码的字符串,里面记录的信息就是转换后代码中的字符与转换前代码中的字符之间的映射关系
  1. 修改配置文件
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,hot: true},devtool: 'eval-source-map'
};/*source-map: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-mapsource-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加入内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快开发环境:速度快,调试更友好速度快(eval>inline>cheap>...)eval-cheap-souce-mapeval-source-map调试更友好  souce-mapcheap-module-souce-mapcheap-souce-map--> eval-source-map  / eval-cheap-module-souce-map生产环境:源代码要不要隐藏? 调试要不要更友好内联会让代码体积变大,所以在生产环境不用内联nosources-source-map 全部隐藏hidden-source-map 只隐藏源代码,会提示构建后代码错误信息--> source-map / cheap-module-souce-map
*/
  1. 运行指令: webpack

5.2 生产环境性能优化

5.2.1 优化打包构建速度
oneOf

打包时每个文件都会经过所有 loader 处理,虽然因为 test
正则原因实际没有处理上,但是都要过一遍。比较慢。所以使用OneOf,匹配上一个 loader, 剩下的就不匹配了。开发模式和生产模式都可以用

配置文件

const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';// 复用loader
const commonCssLoader = [MiniCssExtractPlugin.loader,'css-loader',{// 还需要在package.json中定义browserslistloader: 'postcss-loader',options: {ident: 'postcss',plugins: () => [require('postcss-preset-env')()]}}
];module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},module: {rules: [{// 在package.json中eslintConfig --> airbnbtest: /\.js$/,exclude: /node_modules/,// 优先执行enforce: 'pre',loader: 'eslint-loader',options: {fix: true}},{// 以下loader只会匹配一个// 注意:不能有两个配置处理同一种类型文件oneOf: [{test: /\.css$/,use: [...commonCssLoader]},{test: /\.less$/,use: [...commonCssLoader, 'less-loader']},/*正常来讲,一个文件只能被一个loader处理。当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:先执行eslint 在执行babel*/{test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader',options: {presets: [['@babel/preset-env',{useBuiltIns: 'usage',corejs: {version: 3},targets: {chrome: '60',firefox: '50'}}]]}},{test: /\.(jpg|png|gif)/,loader: 'url-loader',options: {limit: 8 * 1024,name: '[hash:10].[ext]',outputPath: 'imgs',esModule: false}},{test: /\.html$/,loader: 'html-loader'},{exclude: /\.(js|css|less|html|jpg|png|gif)/,loader: 'file-loader',options: {outputPath: 'media'}}]}]},plugins: [new MiniCssExtractPlugin({filename: 'css/built.css'}),new OptimizeCssAssetsWebpackPlugin(),new HtmlWebpackPlugin({template: './src/index.html',minify: {collapseWhitespace: true,removeComments: true}})],mode: 'production'
};
babel缓存

目标:让第二次打包构建速度更快。
在babel-loader配置中添加缓存配置:cacheDirectory: true

const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');/*缓存:babel缓存cacheDirectory: true--> 让第二次打包构建速度更快文件资源缓存hash: 每次wepack构建时会生成一个唯一的hash值。问题: 因为js和css同时使用一个hash值。如果重新打包,会导致所有缓存失效。(可能我却只改动一个文件)chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样问题: js和css的hash值还是一样的因为css是在js中被引入的,所以同属于一个chunkcontenthash: 根据文件的内容生成hash值。不同文件hash值一定不一样    --> 让代码上线运行缓存更好使用
*/// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';// 复用loader
const commonCssLoader = [MiniCssExtractPlugin.loader,'css-loader',{// 还需要在package.json中定义browserslistloader: 'postcss-loader',options: {ident: 'postcss',plugins: () => [require('postcss-preset-env')()]}}
];module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.[contenthash:10].js',path: resolve(__dirname, 'build')},module: {rules: [{// 在package.json中eslintConfig --> airbnbtest: /\.js$/,exclude: /node_modules/,// 优先执行enforce: 'pre',loader: 'eslint-loader',options: {fix: true}},{// 以下loader只会匹配一个// 注意:不能有两个配置处理同一种类型文件oneOf: [{test: /\.css$/,use: [...commonCssLoader]},{test: /\.less$/,use: [...commonCssLoader, 'less-loader']},/*正常来讲,一个文件只能被一个loader处理。当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:先执行eslint 在执行babel*/{test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader',options: {presets: [['@babel/preset-env',{useBuiltIns: 'usage',corejs: { version: 3 },targets: {chrome: '60',firefox: '50'}}]],// 开启babel缓存// 第二次构建时,会读取之前的缓存cacheDirectory: true}},{test: /\.(jpg|png|gif)/,loader: 'url-loader',options: {limit: 8 * 1024,name: '[hash:10].[ext]',outputPath: 'imgs',esModule: false}},{test: /\.html$/,loader: 'html-loader'},{exclude: /\.(js|css|less|html|jpg|png|gif)/,loader: 'file-loader',options: {outputPath: 'media'}}]}]},plugins: [new MiniCssExtractPlugin({filename: 'css/built.[contenthash:10].css'}),new OptimizeCssAssetsWebpackPlugin(),new HtmlWebpackPlugin({template: './src/index.html',minify: {collapseWhitespace: true,removeComments: true}})],mode: 'production',devtool: 'source-map'
};
多进程打包
  1. 安装 loader 包
npm i thread-loader -D
  1. 修改配置文件
/*** 多进程打包* 1.下载thread-loader——》cnpm i thread-loader -D* 2.哪个loader需要多进程打包就使用该loader,一般给babel-loader使用,使用如下:*      // 对js进行兼容性处理{test: /\.js$/,exclude: /node_modules/,use: [// 开启多进程打包// 启动进程600ms,进程通信也有开销// 只有工作消耗时间比较长,才使用多进程打包'thread-loader',{loader: 'babel-loader',options: {presets: ["@babel/preset-env"],plugins: [["@babel/plugin-transform-runtime"]],//开启缓存,第二次构建时,只处理发生变化的js文件cacheDirectory:true},},]},*/
const { resolve } = require('path');
// 引入workbox
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 将css单独提出文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 引入压缩插件
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
// 将通用的loader抽离出来
// 设置nodejs的环境变量
// process.env.NODE_ENV = 'development';
const commonLoaders = [MiniCssExtractPlugin.loader, // 使用该loader将js中的css导入到文件中,并引入html文件'css-loader',{loader: 'postcss-loader',options: {postcssOptions: {ident: 'postcss',plugins: [['postcss-preset-env', {}]]}},},
]
module.exports = {mode: 'development',// 单入口// entry: './src/js/index.js',// 多入口:有几个入口就输出几个bundle// entry: {//     index: './src/js/index.js',//     test: './src/js/test.js',// },entry: ['babel-polyfill', './src/js/index.js', './src/index.html'],output: {filename: 'js/[name][contenthash:10].js',path: resolve(__dirname, 'build')},module: {rules: [{// 以下loader只会匹配一下,提升构建速度// 注意:不能有两个loader处理同一个文件oneOf: [// 对js进行兼容性处理{test: /\.js$/,exclude: /node_modules/,use: ['thread-loader',{loader: 'babel-loader',options: {presets: ["@babel/preset-env"],plugins: [["@babel/plugin-transform-runtime"]],//开启缓存,第二次构建时,只处理发生变化的js文件cacheDirectory:true},},]},// css文件处理{test: /\.css$/,use: [...commonLoaders],},// less文件处理{test: /\.less$/,use: [...commonLoaders,'less-loader'],},// image图片处理{test: /\.(jpg|png|gif)$/,type:"asset",//解析parser: {//转base64的条件dataUrlCondition: {maxSize: 8 * 1024, // 8kb}},generator:{ //与output.assetModuleFilename是相同的,这个写法引入的时候也会添加好这个路径filename:'img/[name][contenthash:10].[ext]',//打包后对资源的引入,文件命名已经有/img了publicPath:'./'},},// 处理html中的image资源{test: /\.html$/,loader: 'html-loader',generator:{ //与output.assetModuleFilename是相同的,这个写法引入的时候也会添加好这个路径filename:'img/[name][contenthash:10].[ext]',//打包后对资源的引入,文件命名已经有/img了publicPath:'./'},},// 字体图标等其他资源处理{exclude: /\.(html|css|js|jpg|png|gif)$/,type: 'asset/resource',generator:{ //与output.assetModuleFilename是相同的,这个写法引入的时候也会添加好这个路径filename:'otherSource/[name][contenthash:10].[ext]',//打包后对资源的引入,文件命名已经有/img了publicPath:'./'},},]},],},plugins: [new HtmlWebpackPlugin({template: './src/index.html',}),// 使用miniCssExtractPlugin插件将css提取为一个文件new MiniCssExtractPlugin({// 对输出的文件重命名filename: 'css/built[contenthash:10].css',}),// 调用压缩css插件new OptimizeCssAssetsWebpackPlugin(),// 调用PWA插件new WorkboxWebpackPlugin.GenerateSW({/*** 1.帮助serviceworker快速启动* 2.删除旧的serviceworker*  生成一个serviceworker的配置文件*/clientsClaim: true,skipWaiting: true,}),],devServer: {// 开发服务器项目路径static: resolve(__dirname, 'build'),// 是否开启gzip压缩compress: true,// 端口号port: 3000,// 是否自动打开浏览器open: true,// 打开HMR功能hot: true,},// 开启追踪源代码报错功能devtool: 'eval-source-map',// 使用代码分割功能/*** 可以将node_modules中的代码单独打包成一个trunk最终输出* 自动分析多入口文件中,是否有公共的依赖,如果有会打包成一个单独的trunk*/optimization: {splitChunks: {chunks: 'all'}},
}
externals

externals 配置项提供了阻止将某些 import 的包(package)打包到 bundle
中的功能,在运行时(runtime)再从外部获取这些扩展依赖(external dependencies)
externals用法:

module.exports={configureWebpack:congig =>{externals:{key: value}}
}

语法说明:

  • key是第三方依赖库的名称,同package.json文件中的dependencies对象的key一样
  • value值可以是字符串、数组、对象。应该是第三方依赖编译打包后生成的js(要用CDN引入的js文件)文件,执行后赋值给window的全局变量名称。

配置文件

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/js/index.js',output: {filename: 'js/built.js',path: resolve(__dirname, 'build')},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})],mode: 'production',externals: {// 拒绝jQuery被打包进来jquery: 'jQuery'}
};
dll

dll的功能就是对代码分割的一种高级应用,将项目中很少变动的依赖先配置出来,提前打包在一个文件中,然后以script标签的方式注入到index.html文件中,接着在build配置中引入打包好的dll配置,这样build执行时会跳过dll中已经打包的模块,从而加快了build的打包时间

  1. 创建webpack.dll.js配置文件,配置需要单独打包的js
/*** 使用dll技术,对某些库(第三方库:jquery、react、vue...)进行单独打包*   当你运行webpack时,默认查找webpack.config.js配置文件*   需求:需要运行 webpack.dll.js 文件*   --> webpack --config webpack.dll.js*   将下面配置的jquery单独打包到dll文件夹下,下面需要将打包的jquery重新引入到我们的项目中*/const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {mode: 'production',entry: {// 最终打包生成的[name]-->jquery// ['jquery']-->要打包的库是jqueryjquery: ['jquery']},// 输出文件output: {filename: '[name].js', // 生成的文件名path: resolve(__dirname, 'dll'),library: '[name]_[hash]', // 打包的库里面向外暴露出去的内容叫什么名字},plugins: [new webpack.DllPlugin({name: '[name]_[hash]', // 映射库的暴露的内容名称path: resolve(__dirname, 'dll/manifest.json') // 输出文件路径}),],
}
  1. 执行命令:webpack --config webpack.dll.js
  2. 修改配置webpack.config.js文件,将单独打包的js引入到我们的入口文件

/*** 将webpack.dll插件打包的文件导入到index.js中*  1、配置webpack.DllReferencePlugin,告诉webpack哪些包要打包,哪些不用打包,以及其映射名称*  2、下载安装:cnpm i add-asset-html-webpack-plugin -D*  3、配置插件:*     // 将某个文件打包输出,并在html中引入该资源*     // 将某个文件打包输出,并在html中引入该资源new AddAssetHtmlWebpackPlugin({// 指定要打包的文件路径filepath: resolve(__dirname, 'dll/jquery.js'),// 输出目录outputPath: 'dll',// html引入的路径publicPath: './dll',attributes: {nomodule: false,},}),*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = {// 模式mode: 'development',// 入口文件entry: './src/index.js',// 输出output: {filename: 'built.js',path: resolve(__dirname, 'build'),},module: {// 需要使用的loaderrules: []},// 插件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'),// 输出目录outputPath: 'dll',// html引入的路径publicPath: './dll',attributes: {nomodule: false,},}),],
}
5.2.2 优化代码运行的性能
缓存(hash-chunkhash-contenthash)

浏览器在多次访问静态资源文件的时候,如果该文件已经在本地缓存,并且它的名称没有改变,那么浏览器会认为它没有被更新,便不会去请求服务器,而是使用该静态资源的缓存版本。如果某个文件被更改,我们希望浏览器应该重新请求它,而不是使用缓存版本,所以文件被修改后,它的名称也应该被改变。

在 webpack 中,最后生成的 chunk 文件都是由一个个的 module 编译后组合而成的,浏览器请求的 JS文件实际上就是一个个的 chunk 。当我们修改某个 module 后,其所属 chunk 打包后的 JS文件名称应该也要发生变化,否则浏览器是不会请求最新版本的 JS 文件的!

输出文件名

在 webpack 中,有 3 种哈希占位符,通过它们修改文件名来控制缓存。

  • hash:只要改动某个模块,所有 chunk 的 hash 都会被修改(不常用);
  • chunkhash:只要改动某个模块,依赖它的 chunk 的 hash 就会被修改(常用);
  • contenthash:只要改动某个模块,这个模块的 hash 就会被更改 ,通常用于被抽离的代码,如抽离 css 。如果不抽离该模块,contenthash 和 chunkhash 的产生的效果一致 (常用,webpack3 不支持 contenthash);

当 hash 变化后,文件名就会变化(如果输出文件名使用了上面的 3 中哈希占位符),浏览器就会去重新请求对应的资源。

hash

准备测试的文件。

//index1.js
console.log('index1.js');
import('./async').then((res) => {console.log(res);
})
//index2.js
console.log('index2.js');
import('./async').then((res) => {console.log(res);
})
//async.js
console.log('async.js');
export default  {desc: 'async.js'
}
//webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin');
var {CleanWebpackPlugin
} = require('clean-webpack-plugin');
module.exports = {mode: 'development',watch: true,entry: {index1: './index1.js',index2: './index2.js'},output: {publicPath: '',path: __dirname + '/dist',//配置hashfilename: '[name].[hash:16].js'},module: {rules: []},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({template: './index.html'}),]
}

编译后控制台打印如下。

                     Asset       Size  Chunks                         Chunk Names0.a535734c8f8ddf89.js  515 bytes       0  [emitted] [immutable]index.html  374 bytes          [emitted]
index1.a535734c8f8ddf89.js   8.54 KiB  index1  [emitted] [immutable]  index1
index2.a535734c8f8ddf89.js   8.53 KiB  index2  [emitted] [immutable]  index2

可以发现,所有 chunk 的 hash 都是 a535734c8f8ddf89 。

修改 async.js、index1.js 或 index2.js 其中的某个文件都将导致所有 chunk 重新构建,这里修改async.js 后,控制台打印如下。

                     Asset       Size  Chunks                         Chunk Names0.160f75be0b2a9d7a.js  519 bytes       0  [emitted] [immutable]index.html  374 bytes          [emitted]
index1.160f75be0b2a9d7a.js   8.54 KiB  index1  [emitted] [immutable]  index1
index2.160f75be0b2a9d7a.js   8.53 KiB  index2  [emitted] [immutable]  index2

可以发现,每次的改动都将导致整个项目重新构建。

chunkhash

把 webpack.config.js 中输出配置名称中的 hash 改为 chunkhash 。

//webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin');
var {CleanWebpackPlugin
} = require('clean-webpack-plugin');
module.exports = {mode: 'development',watch: true,entry: {index1: './index1.js',index2: './index2.js'},output: {publicPath: '',path: __dirname + '/dist',filename: '[name].[chunkhash:16].js'},module: {rules: []},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({template: './index.html'}),]
}

编译构建后,控制台打印如下。

                     Asset       Size  Chunks                         Chunk Names0.ef0a90ca4be41633.js  519 bytes       0  [emitted] [immutable]index.html  374 bytes          [emitted]
index1.e04fb78630b9ed06.js   8.55 KiB  index1  [emitted] [immutable]  index1
index2.a82fa8cf316672d3.js   8.54 KiB  index2  [emitted] [immutable]  index2

可以发现每个 chunk 都有自己的专属 hash,在修改 index1.js 或 index2.js 的时候,也只会导致被修改的文件所属的
chunk 重新构建。

修改 index1.js 后,控制台打印如下。

                     Asset       Size  Chunks                         Chunk Namesindex.html  374 bytes          [emitted]
index1.219644b9fa78ecf2.js   8.53 KiB  index1  [emitted] [immutable]  index1

修改 index2.js 后,控制台打印如下。

                     Asset       Size  Chunks                         Chunk Namesindex.html  374 bytes          [emitted]
index2.2fb396992e95ea30.js   8.53 KiB  index2  [emitted] [immutable]  index2

修改 async.js 后,控制台打印如下。

                     Asset       Size  Chunks                         Chunk Names0.ef0a90ca4be41633.js  519 bytes       0  [emitted] [immutable]index.html  374 bytes          [emitted]
index1.b19fb895cd7844da.js   8.53 KiB  index1  [emitted] [immutable]  index1
index2.89c07defcd285597.js   8.53 KiB  index2  [emitted] [immutable]  index2

index1.js 和 index2.js 所属的 chunk 重新构建了,这是因为 index1 chunk 和 index2 chunk需要懒加载 async.js ,而懒加载 async.js 是根据 async.js 所属的 chunk 打包后的文件名来加载的,当 async.js 发生变化后,它所属的 chunk 打包后的文件名会因为 hash 变化而变化,index1 chunk 和 index2 chunk 中懒加载 相关的的路径名称也跟着发生了变化,从而导致 index1 chunk 和 index2 chunk 的 hash变化而重新构建。

因为懒加载流程是属于 runtime (安装、加载和连接模块的逻辑)部分的代码,所以可以将 runtime 部分的代码抽离出来,然后再次修改 async.js ,发现 index1 chunk 和 index2 chunk 的代码就不会重新构建了。

//webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin');
var {CleanWebpackPlugin
} = require('clean-webpack-plugin');
module.exports = {mode: 'development',watch: true,entry: {index1: './index1.js',index2: './index2.js'},output: {publicPath: '',path: __dirname + '/dist',filename: '[name].[chunkhash:16].js'},module: {rules: []},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({template: './index.html'}),],optimization: {// 'single' - 表示抽离所有 chunk 公用的 runtime 代码runtimeChunk: 'single' }
}

编译打包后,控制台打印如下。

                      Asset       Size   Chunks                         Chunk Names0.ef0a90ca4be41633.js  519 bytes        0  [emitted] [immutable]index.html  425 bytes           [emitted]index1.ce2de40546b020f7.js  545 bytes   index1  [emitted] [immutable]  index1index2.cf1286e262093666.js  553 bytes   index2  [emitted] [immutable]  index2
runtime.a0f05e8cde7456ae.js   8.97 KiB  runtime  [emitted] [immutable]  runtime

修改 async.js 后,控制台打印如下。

                      Asset       Size   Chunks                         Chunk Names0.0f79481d25aeed80.js  523 bytes        0  [emitted] [immutable]index.html  425 bytes           [emitted]
runtime.fa3fbcea2005af1c.js   8.97 KiB  runtime  [emitted] [immutable]  runtime

这下 index1.js 和 index2.js 对应的 chunk 便不会重新构建了,因为我们把连接模块的逻辑都抽离出来了,改变async.js 会导致 async.js 和 runtime 代码对应的 chunk 重新构建。

contenthash

contenthash 只有在抽离某个 module 的时候才会显示它的作用,否则它和 chunkhash 的表现一致,这里以抽离 css为例。先安装 css-loader 和 mini-css-extract-plugin 。

yarn add css-loader mini-css-extract-plugin -d
//index1.css
body , html {height: 100%;width: 100%;margin: 0;padding: 0;
}//index1.js
console.log('index1.js');
import('./async').then((res) => {console.log(res);
})
import './index1.css';//webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ProgressPlugin = require('webpack').ProgressPlugin;
var MiniCssExtractPlugin = require('mini-css-extract-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin;
module.exports = {mode: 'development',watch: true,entry: {index1: './index1.js',index2: './index2.js'},output: {publicPath: '',path: __dirname + '/dist',filename: '[name].[chunkhash].js'},module: {rules: [{test: /\.css$/,use: [MiniCssExtractPlugin.loader, // 抽取css文件的loader,不再插入head里'css-loader']}]},plugins: [new ProgressPlugin(),new CleanWebpackPlugin(),new MiniCssExtractPlugin({filename: '[name].[contenthash].css'}),new HtmlWebpackPlugin({template: './index.html',})],optimization: {// 'single' - 表示抽离所有 chunk 公用的 runtime 代码runtimeChunk: 'single'}
}

编译打包后,控制台打印如下。

                          Asset       Size   Chunks                         Chunk Names0.a84498019577afde7588.js   1.07 KiB        0  [emitted] [immutable]index.html  499 bytes           [emitted]index1.470f6e18ca06585dd954.js   1.07 KiB   index1  [emitted] [immutable]  index1
index1.8db6dca1b242dbbabe70.css   87 bytes   index1  [emitted] [immutable]  index1index2.82d191b5754b0e2e2ca8.js  537 bytes   index2  [emitted] [immutable]  index2
runtime.fca50e4fde877e19576a.js   8.98 KiB  runtime  [emitted] [immutable]  runtime

修改 index1.js 后,控制台打印如下。

                         Asset       Size  Chunks                         Chunk Namesindex.html  499 bytes          [emitted]
index1.2748748868607facc4a8.js   1.08 KiB  index1  [emitted] [immutable]  index1

index1.css 和 index1.js 都属于 index1 这个 chunk 。当修改 index1.js 后,并不会引起indx1.css 重新构建,因为 index1.css 不依赖 index1.js 。contenthash 的作用就是:当模块自身发生变化的时候,才会去重新构建这个模块。

tree shaking

Tree-shaking
它的名字来源于通过摇晃(shake)JavaScript代码的抽象语法树(AST),是一种用于优化JavaScript代码的技术,主要用于移除未被使用的代码,使得最终生成的代码包含应用程序中实际使用的部分。这主要用于减小应用程序的体积,提高加载性能。

在前端开发中,特别是在使用模块化工具(如Webpack、Rollup等)构建应用程序时,通常会引入许多库和模块。然而,应用程序可能只使用了这些库的一小部分功能,导致最终生成的代码包含了大量未被使用的代码。Tree-shaking通过静态分析代码来确定哪些代码是可到达的并且被使用的,然后去除那些未被使用的部分。这样一来,可以显著减小最终部署的代码大小,提高应用程序的性能。

Tree Shaking 较早前由 Rich Harris 在 Rollup 中率先实现,Webpack 自 2.0
版本开始接入,已经成为一种应用广泛的性能优化手段。

1.首先,要明确一点:Tree Shaking 只支持 ESM 的引入方式,不支持 Common JS 的引入方式。

  • ESM: export + import
  • Common JS: module.exports + require

摇树优化是一种在打包编译时移除未使用代码的技术,可以显著减少最终打包文件的大小。为了使 Tree Shaking 有效工作,你的代码必须基于 ES6 模块的静态结构特性。

静态 vs. 非静态结构

  • 静态结构:所有导入和导出都是固定的,不依赖于运行时条件。

    import a from './a';
    import b from './b';
    export default a;
    
  • 非静态结构:导入或导出依赖于运行时变量或条件语句。

    console.log('index.js');
    const flag = Math.random();
    if (flag) {module.exports = 1;
    } else {module.exports = {};
    }if (flag) {require('./a.js');
    } else {require('./b.js');
    }
    

准备 Demo

  • unused.js

    const a = 1;
    const b = () => {return 'test.js';
    };
    export {a, b};
    
  • math.js

    export function add(a, b) {return a + b;
    }
    export function sub(a, b) {return a - b;
    }
    
  • index.js

    import {add} from './math';
    import * as unused from './unused';const result = add(55, 45);
    console.log(result);
    

开发环境测试

  • webpack.config.js(开发模式):

    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var { CleanWebpackPlugin } = require('clean-webpack-plugin');module.exports = {mode: 'development',entry: {index: './index.js',},optimization: {usedExports: true,},output: {publicPath: '',path: __dirname + '/dist',filename: '[name].js'},module: {rules: []},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({template: './index.html'}),]
    };
    

    在开发环境下,即使配置了 optimization.usedExports: true,WebPack 只会标记未使用的代码,并不会真正删除它们。

生产环境测试

  • webpack.config.js(生产模式):

    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var { CleanWebpackPlugin } = require('clean-webpack-plugin');module.exports = {mode: 'production',entry: {index: './index.js',},output: {publicPath: '',path: __dirname + '/dist',filename: '[name].js'},module: {rules: []},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({template: './index.html'}),]
    };
    

    在生产模式下,WebPack 会对代码进行极致优化,未使用的代码会被移除。

sideEffects

sideEffects 是指有副作用的代码,例如修改全局变量或对象的属性。如果模块中包含这样的代码,那么即使该模块的部分导出未被使用,整个模块也可能不会被 Tree Shaking 掉。

  • 如果项目中的所有模块都没有副作用,可以在 package.json 中设置 "sideEffects": false 来加速 Tree Shaking 过程。

  • 如果某些特定的模块具有副作用,可以在 package.json 中指定这些模块的路径。

  • package.json 示例:

    {"name": "webpack","version": "1.0.0","main": "index.js","license": "MIT","scripts": {"dev": "webpack"},"sideEffects": ["./math.js"]
    }
    

通过以上步骤,你可以有效地利用 Tree Shaking 技术来优化你的 JavaScript 应用程序。确保在生产构建中启用适当的 Webpack 设置以获得最佳效果。

code split

Webpack 提供了几种不同的方法来实现代码分离,以优化加载时间和用户体验。以下是三种主要的代码分离方式:

  1. 入口起点(Entry Points)
  2. 防止重复(使用 SplitChunksPlugin 去重和分离 chunk)
  3. 动态导入(通过模块的内联函数调用懒加载)

1. 入口起点

通过配置多个入口点,可以将项目代码分割成多个独立的 chunk。

  • index.js

    console.log('index.js');
    
  • index2.js

    console.log('index2.js');
    
  • webpack.config.js

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');module.exports = {mode: 'development',entry: {index: './index.js',index2: './index2.js'},output: {publicPath: '',path: __dirname + '/dist',filename: '[name].js'},module: {rules: []},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({ template: './index.html' })]
    };
    

打包后的目录结构会包含两个独立的 chunk 文件:index.jsindex2.js
在这里插入图片描述

2. 动态导入

利用 JavaScript 的动态 import() 语法,可以在运行时按需加载模块,从而实现代码的懒加载。

  • index.js

    console.log('index.js');import('./async').then((res) => {console.log(res);
    });import('./async2').then((res) => {console.log(res);
    });
    
  • webpack.config.js

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');module.exports = {mode: 'development',entry: {index: './index.js'},output: {publicPath: '',path: __dirname + '/dist',filename: '[name].js',chunkFilename: '[name].async.js'},module: {rules: []},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({ template: './index.html' })]
    };
    

打包后的目录结构会包含三个 chunk 文件:index.js0.async.js1.async.js
在这里插入图片描述

3. 防止重复(使用 SplitChunksPlugin)

当多个 chunk 引入了相同的模块时,可以通过 SplitChunksPlugin 来提取这些公共模块,避免重复打包。

  • initial-common.js

    function initialCommon(a, b) {return a * b;
    }
    var res = initialCommon(1, 2);
    console.log(res);
    
  • async-common.js

    function asyncCommon(a, b) {return a * b;
    }
    var res = asyncCommon(1, 2);
    console.log(res);
    
  • index1-async1-common.js

    function index1Async1Common(a, b) {return a * b;
    }
    var res = index1Async1Common(1, 2);
    console.log(res);
    
  • async1.js

    console.log('async1.js');
    import './async-common';
    import './index1-async1-common';
    
  • async2.js

    console.log('async2.js');
    import './async-common';
    
  • index1.js

    console.log('index1.js');
    import './initial-common';
    import './index1-async1-common';import('./async1').then((res) => {console.log(res);
    });import('./async2').then((res) => {console.log(res);
    });
    
  • index2.js

    console.log('index2.js');
    import './initial-common';
    
  • webpack.config.js

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');module.exports = {mode: 'development',entry: {index1: './index1.js',index2: './index2.js'},output: {publicPath: '',path: __dirname + '/dist',filename: '[name].js',chunkFilename: '[name].async.js'},module: {rules: []},plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({ template: './index.html' })],optimization: {splitChunks: {chunks: 'all',minSize: 0,minChunks: 2,automaticNameDelimiter: '~',cacheGroups: {vendors: {test: /[\\/]node_modules[\\/]/,priority: -10},common: {priority: -20,reuseExistingChunk: true}}}}
    };
    

打包后的目录结构将会根据配置生成相应的 chunk 文件,并且共享的代码会被提取到单独的文件中,例如 common~index1~index2.async.js0.async.js 等。

在这里插入图片描述

懒加载/预加载

1. 基本配置

首先,我们需要一个基本的 Webpack 配置文件,这里使用单入口形式:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = {mode: "production",entry: "./src/js/index.js", // 单入口output: {filename: "js/[name].[contenthash:10].js",path: path.resolve(__dirname, "build"),},plugins: [new HtmlWebpackPlugin({template: "./src/index.html", // 引用 HTML 模板minify: { // 压缩 HTMLcollapseInlineTagWhitespace: true,removeComments: true,}}),],optimization: {splitChunks: {chunks: 'all' // 可以将 node_modules 中的模块单独打包成一个 chunk}},devtool: 'source-map',
};

2. 懒加载 (Lazy Loading)

懒加载是一种按需加载代码的技术,它允许你只在需要时才加载特定的 JavaScript 模块。这可以显著减少初始加载时间,并提高应用性能。

2.1 动态导入语法

Webpack 支持 ES6 的 import() 语法来进行动态导入。这种语法返回一个 Promise,可以用来异步加载模块。

  • 示例代码

    // src/js/index.js
    console.log('index.js 被加载了');document.getElementById('btn').onclick = async function() {const { mul } = await import(/* webpackChunkName: 'test' */ './test');console.log(mul(4, 5));
    };
    
  • 懒加载模块 (src/js/test.js):

    export function mul(a, b) {return a * b;
    }
    
  • HTML 文件 (src/index.html):

    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Lazy Loading Example</title>
    </head>
    <body><h1>Lazy Loading with Webpack</h1><button id="btn">Load Test Module</button>
    </body>
    </html>
    

通过上述配置,当你点击按钮时,test.js 将会被按需加载,而不是在页面初始化时就加载。

3. 预加载 (Preloading)

预加载是一种在后台提前加载资源的技术,可以在用户真正需要这些资源之前就开始加载它们。这样可以减少用户等待的时间,提高用户体验。

3.1 使用 webpackPrefetch

你可以通过在动态导入语句中添加 webpackPrefetch: true 来实现预加载。

  • 示例代码

    // src/js/index.js
    console.log('index.js 被加载了');document.getElementById('btn').onclick = async function() {const { mul } = await import(/* webpackChunkName: 'test', webpackPrefetch: true */ './test');console.log(mul(4, 5));
    };
    
  • 预加载模块 (src/js/test.js):

    export function mul(a, b) {return a * b;
    }
    
  • HTML 文件 (src/index.html):

    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Preloading Example</title>
    </head>
    <body><h1>Preloading with Webpack</h1><button id="btn">Load Test Module</button>
    </body>
    </html>
    

在上述配置中,import(/* webpackChunkName: 'test', webpackPrefetch: true */ './test') 会生成一个预加载的 <link> 标签,以便在浏览器空闲时预先加载 test.js

4. 区别与总结

  • 懒加载:通过动态导入 import() 语法,在需要时异步加载模块。
  • 预加载:通过 webpackPrefetch: true 注释,在浏览器空闲时提前加载可能需要的资源。

区别:

  1. 预加载会在使用之前提前请求 JS 文件,但不会立即调用;懒加载是当文件被需要时才会请求。
  2. 正常加载被认为是并行加载(同一时间加载多个文件),但可能没有人使用,所以提倡懒加载。
  3. 懒加载中的预加载会在其他文件加载完毕后,在浏览器空闲的时候进行预加载,以备打算使用该模块的人等待时间过长。

通过合理使用懒加载和预加载,你可以显著提升应用的加载性能和用户体验。确保在实际项目中根据具体需求选择合适的加载方式,并进行适当的配置。

PWA(渐进式 Web 应用)配置详解

PWA,即渐进式 Web 应用,是一种利用现代 Web 技术来提供类似原生应用体验的 Web 应用。它支持离线访问、推送通知以及后台同步等功能,极大地增强了用户体验。本文将介绍如何使用 Webpack 配置一个 PWA 项目,并通过示例代码展示其核心功能。

1. Webpack 配置

为了构建一个 PWA,我们需要在 Webpack 配置中添加一些插件和加载器来处理 CSS、JavaScript 以及其他资源文件。此外,我们还需要使用 workbox-webpack-plugin 来生成 Service Worker 文件,以便实现离线缓存和其他 PWA 功能。

基本配置

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin"); // HTML 模板
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 提取 CSS
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin"); // 压缩 CSS
const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); // 使用 PWA
process.env.NODE_ENV = "production";// 复用 CSS 的 loader
let commonCssLoader = [{loader: MiniCssExtractPlugin.loader,options: {publicPath: '../', // 避免 CSS 中的路径引入错误}},'css-loader',{loader: 'postcss-loader',options: {ident: 'postcss',plugins: () => [require('postcss-preset-env')()]}}
];module.exports = {mode: "production", // 生产模式entry: "./src/js/index.js",output: {filename: "built.[contenthash:10].js",path: path.resolve(__dirname, "build")},module: {rules: [// CSS 和 Less{test: /\.css$/,use: [...commonCssLoader]},{test: /\.less$/,use: [...commonCssLoader, 'less-loader']},// JavaScript 兼容性处理{test: /\.js$/,exclude: /node_modules/,loader: "babel-loader",options: {presets: [["@babel/preset-env",{useBuiltIns: "usage",corejs: { version: 3 },targets: {chrome: "60",firefox: "60",ie: "9",safari: "10",edge: "17"}}]],cacheDirectory: true}},// 图片处理{test: /\.(jpg|png|gif)$/,loader: 'url-loader',options: {limit: 8 * 1024,name: '[contenthash:10].[ext]',outputPath: 'imgs',esModule: false}},// HTML 处理{test: /\.html$/,loader: 'html-loader'},// 其他资源处理{exclude: /\.(js|html|css|less|json|jpg|png|gif)$/,loader: 'file-loader',options: {outputPath: 'media'}}]},plugins: [new HtmlWebpackPlugin({template: "./src/index.html", // 引用 HTML 模板minify: { // 压缩 HTMLcollapseInlineTagWhitespace: true,removeComments: true}}),new MiniCssExtractPlugin({filename: "css/built.[contenthash:10].css" // 设置 CSS 输出}),new OptimizeCssAssetsWebpackPlugin(), // 压缩 CSS 插件new WorkboxWebpackPlugin.GenerateSW({ // 生成 Service WorkerclientsClaim: true,skipWaiting: true})]
};

2. 主入口文件 (index.js)

主入口文件需要导入样式和执行必要的逻辑,并且注册 Service Worker 以启用 PWA 特性。

import '../css/c.less';
import '../css/a.css';
import '../css/b.css';
import '../css/iconfont.css';
import '../css/index.css';
import { mul } from './test';const add = (x, y) => x + y;
new Promise((resolve) => {console.log('promise');setTimeout(() => {console.log('timeout');resolve();}, 0);
}).then(() => {console.log('p_end');
});
console.log(add(2, 3));console.log(mul(3, 3));// 注册 Service Worker
if ('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/service-worker.js').then((res) => {console.log('注册 service-worker 成功', res);}).catch((e) => {console.log(e);});});
}

3. ESLint 配置

如果你希望 ESLint 支持浏览器全局变量,可以在 package.json 中添加或修改 eslintConfig 字段:

{"eslintConfig": {"env": {"browser": true,"es6": true},"extends": "eslint:recommended","rules": {// 自定义规则}}
}

4. 离线访问验证

当你的 PWA 应用已经部署并且 Service Worker 已经注册后,你可以尝试断开网络连接并刷新页面,检查是否仍然可以正常加载。如果一切设置正确,你应该能看到应用依然可用,并且控制台会显示从 Service Worker 缓存中加载资源的信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/881984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML(七)表格

https://chatgai.lovepor.cn/ 在HTML中&#xff0c;表格的标准形式如下&#xff1a; <table></table> 使用上面的语言&#xff0c;就已经生成了一个表格&#xff0c;只不过这个表格什么都没有 那么&#xff0c;该如何让表格存在东西呢&#xff1f; 首先&#xf…

springboot 整合spring ai实现 基于知识库的客服问答

rag 需求产生的背景介绍&#xff1a; 在使用大模型时&#xff0c;常遇到的问题之一是模型可能产生幻觉&#xff0c;即生成的内容缺乏准确性。此外&#xff0c;由于大模型不直接访问企业的专有数据&#xff0c;其响应可能会显得泛泛而谈&#xff0c;不够精准或具体&#xff0c;…

基于YOLOv10的农场实时目标检测系统(python+pyside6界面+系统源码+可训练的数据集+也完成的训练模型)

摘要&#xff1a; 基于YOLOv10的农场实时目标检测系统&#xff0c;利用4393张图片&#xff08;3905张训练集&#xff0c;488张验证集&#xff09;进行模型训练&#xff0c;最终开发出一个高效的农场目标检测模型。为了方便用户操作和实时检测&#xff0c;本系统还开发了基于Pyt…

VSCode运行QT界面

VSCode用久了,感觉Qt Creator的写起代码来还是不如VSCode得心应手,虽然目前还是存在一些问题,先把目前实现的状况做个记录,后续有机会再进一步优化。 当前方式 通过QtCreator创建一个CMake项目,然后使用CMake的方式在VSCode中进行编译。 claude给出的建议 左上角的名字会…

SiLM27212 270V 4A/4A 支持高频信号输入 集成自举二极管的高低边门极驱动器

SiLM27212系列选型&#xff1a; SiLM27212LEK-DG SiLM27212EK-DG SiLM27212LCA-DG SiLM27212CA-DG SiLM27212LCB-DG SiLM27212CB-DG SiLM27212系列是一款支持高频信号输入的高低边N沟道MOSFET驱动器&#xff0c;有着优异的性能&#xff0c;广泛应用于各类模…

Linux查看下nginx及使用的配置文件

1、查到nginx进程 ps -aef | grep nginx2、通过进行pid查到nginx路径 pwdx <pid>3、根据路径得到配置文件 path***/nginx -t如下&#xff1a;

MacOS虚拟机安装Windows停滞在“让我们为你连接到网络”,如何解决?

1. 问题描述 MacOS在虚拟机安装win11过程中&#xff0c;停止在“让我们为你连接到网络”步骤&#xff0c;页面没有任何可以点击的按钮&#xff0c;进行下一步操作。 2. 解决方案&#xff08;亲测有效&#xff09; 到达该界面&#xff0c;按下ShiftF10&#xff08;Windows&…

【机器学习】深入浅出讲解贝叶斯分类算法

0. 前言 1.贝叶斯分类器介绍 贝叶斯分类是一类分类算法的总称&#xff0c;这类算法均以贝叶斯定理为基础&#xff0c;故统称为贝叶斯分类。而朴素贝叶斯&#xff08;Naive Bayes&#xff09;分类是贝叶斯分类中最简单&#xff0c;也是常见的一种分类方法。 一些很常见的分类…

整理—计算机网络

目录 网络OSI模型和TCP/IP模型 应用层有哪些协议 HTTP报文有哪些部分 HTTP常用的状态码 Http 502和 504 的区别 HTTP层请求的类型有哪些&#xff1f; GET和POST的使用场景&#xff0c;有哪些区别&#xff1f; HTTP的长连接 HTTP默认的端口是什么&#xff1f; HTTP1.1怎…

哪科竞赛含金量更高?五大学科竞赛含金量排名

2024年五大学科竞赛赛事已经渐渐拉开帷幕&#xff0c;本月底国内不少地区即将举行生物竞赛预赛的赛事。今天我们一起来看看五大学科竞赛哪科竞赛含金量更高。 高中五大学科竞赛&#xff08;数物化生信&#xff09;是升学路上的硬通货&#xff0c;比如说在强基破格中需要五大竞赛…

揭秘提升3DMAX效率的6款必备神级插件!

对于3DMax新手来说,掌握一些高效、实用的插件能够大大提升工作效率和创作质量。以下是6个不能错过的神级插件推荐: 第1个:3DMAX造山地形插件Mountain是一款专为3dMax设计的插件,旨在帮助用户轻松快速地创建逼真的山脉地形。以下是对该插件的详细介绍: 一、插件概述 Mou…

Xilinx远程固件升级(一)——QuickBoot方案

Xilinx 7系FPGA远程更新方案——QuickBoot方式远程更新bit 一、远程更新背景和架构 对于非ZYNQ系列的常规FPGA来说&#xff0c;对于bit的更新一般使用JTAG进行烧录。而作为商用产品&#xff0c;想要进行OTA升级时&#xff0c;使用JTAG的升级方式显然不适合&#xff0c;因此&a…

Java | Leetcode Java题解之第486题预测赢家

题目&#xff1a; 题解&#xff1a; class Solution {public boolean PredictTheWinner(int[] nums) {int length nums.length;int[] dp new int[length];for (int i 0; i < length; i) {dp[i] nums[i];}for (int i length - 2; i > 0; i--) {for (int j i 1; j …

计算机毕业设计Python动漫视频分析可视化 动漫影视可视化 动漫情感分析 动漫爬虫 机器学习 深度学习 Tensorflow PyTorch LSTM模型

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系名片 &#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系名片 &#xff01; 温馨提示&#xff1a;文末有SDN 平台官方提供的学长联系名片 &#xff01; 基于Python的B站排行榜大数据分析与可视化系统…

最短路问题之dijikstra算法

//根据bfs修改而来 #include<stdio.h> #include<stdlib.h> typedef struct queue {int data;struct queue* next; }queue, * linklist; float dist_list[9]; //出发点为0 int forward_point_list[9] { -1 }; linklist front NULL; linklist rear NULL; float ma…

计算机的错误计算(一百二十五)

摘要 探讨算式 的计算精度问题。 例1. 已知 计算 不妨在 Excel 的单元格中计算&#xff0c;则有&#xff1a; 若在 Python 中计算&#xff0c;则似乎有更为精确的结果&#xff1a; 然而&#xff0c;16位的正确值是 0.3499999999999998e1&#xff08;ISRealsoft 提供&a…

前后端请求一致性学习

在进行前后端分离开发项目的过程中&#xff0c;前后端同学往往需要依照接口文档的基本信息以及相应的响应格式进行接口请求的开发&#xff0c;在这个过程中涉及到常见的Get、Post、Put、Patch等等的请求&#xff0c;相应的前后端的书写格式是什么&#xff0c;这篇文章进行一个记…

数据链中常见电磁干扰matlab仿真,对比噪声调频,线性调频,噪声,扫频,灵巧五种干扰模型

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 噪声调频干扰 4.2 线性调频干扰 4.3 噪声干扰 4.4 扫频干扰 4.5 灵巧干扰 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a 3…

Go语言中的时间比较与时区处理

文章目录 问题背景问题分析验证时区问题 解决方案方法 1&#xff1a;使用本地时区解析时间方法 2&#xff1a;将 time.Now() 转换为 UTC 最终结果总结 在后端开发中&#xff0c;时间处理往往是不可避免的&#xff0c;尤其是涉及到跨时区的应用时&#xff0c;时区问题常常会引发…

【黑马redis高级篇】持久化

//来源[01,05]分布式缓存 除了黑马&#xff0c;还参考了别的。 目录 1.单点redis问题及解决方案2.为什么需要持久化&#xff1f;3.Redis持久化有哪些方式呢&#xff1f;为什么我们需要重点学RDB和AOF&#xff1f;4.RDB4.1 定义4.2 触发方式4.2.1手动触发save4.2.2被动触发bgsa…