webpack5 入门学习笔记(四)性能优化

  • 写在前面
    • webpack优化配置
      • 开发环境性能优化
      • 生产环境性能优化
      • HMR
        • 定义
        • 作用
        • 使用方法
        • 要点记录
        • 代码实现
      • source-map
        • 定义
        • 作用
        • 使用方法
        • 代码实现
      • oneOf
        • 定义
        • 作用
        • 使用方法
        • 要点记录
        • 代码实现
      • 缓存
        • 作用
        • 使用方法
        • 要点记录
        • 代码实现
      • tree shaking
        • 定义
        • 作用
        • 使用方法
        • 要点记录
        • 代码实现
      • code split
        • entry points(入口起点)
          • 定义
          • 使用方法
          • 要点记录
          • 代码实现
        • prevent duplication(防止重复)
          • 定义
          • 使用方法
            • Entry dependencies
            • SplitChunksPlugin
          • 要点记录
          • 代码实现
        • import(动态引入)
          • 定义
          • 使用方法
          • 要点记录
          • 代码实现
      • lary loading
        • 定义
        • 使用方法
        • 要点记录
        • 代码实现
      • PWA
        • 定义
        • 使用方法
        • 要点记录
        • 代码实现
      • 多进程打包
        • 定义
        • 使用方法
        • 要点记录
        • 代码实现
      • external
        • 定义
        • 使用方法
        • 要点记录
        • 代码实现
  • 写在后面

写在前面

webpack优化配置

开发环境性能优化

  • 优化打包构建速度

    • HMR 模块热替换
  • 优化代码调试
    • source-map

生产环境性能优化

  • 优化打包构建速度

    • oneOf
    • babel 缓存
    • 多进程打包 同一时间干多件事,提升打包速度,进程开启和交流也有开销,消耗时间比较长的任务,使用 thread-loader 对 babel-loader 进行优化
    • external 声明不用打包的库,再用 cdn 引进来
  • 优化代码运行的性能
    • 缓存(hash-chunkhash-contenthash)
    • tree shaking (es6 模块,production)(package.json 中 sideEffects:[‘xxx’])
    • code split {单页面,单入口通过 import 引入的一定会被分割成单独的打包,optimization}
    • 懒加载/预加载
      • 代码分割是异步执行,使用懒加载
      • 预加载等其他资源加载完再加载,预加载兼容性问题大用之慎重
    • pwa 离线可访问,serviceworker 和 cache,使网络离线可访问,兼容性问题严重

HMR

定义

  • hot module replacement 热模块替换 / 模块热替换

作用

  • 一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度

使用方法

  1. devServer 中加上 hot:true

     devServer: {hot:true}
    
  2. 样式文件:可以使用 HMR 功能 ,因为 style-loader 内部实现了,所以开发环境下用 style-loader ,但是生产环境下还是提取 css 为单独文件,就不能使用了
       loader:'style-loader'
    
  3. html文件: 默认不能使用 HMR 功能,开启 HMR 同时会导致
    • 问题html 文件不能热更新了
    • 解决:修改 entry 入口,将 html 文件引入( html 文件只有一个,不用做 HMR 功能)
       //入口文件entry:['./src/js/index.js','./src/index.html'],
    
  4. js文件:默认不能使用 HMR 功能 -->需要修改 js 代码,添加支持 HMR 功能的代码
    • 注意HMR 功能对 js 的处理,只能处理非入口 js 文件的其他文件
    • index.js 文件中加入以下代码
     if (module.hot) {//全局中寻找hot//一旦module.hot为true,说明开启了HMR功能。 -->让HMR功能代码生效module.hot.accept('./print.js', function () {//方法会监听print.js文件的变化,一旦发生变化,其他默认不会重新打包构建//会执行后面的回调函数print()})
    }
    

要点记录

  1. 当修改了 webpack 配置,新配置要想生效必须重启 webpack 服务

代码实现

 const { resolve } = require('path');const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {//入口文件entry:['./src/js/index.js','./src/index.html'],//出口output: {//输出的文件名filename: 'js/bundle.js',//输出的路径path: resolve(__dirname, 'dist'),clean:true //清理旧文件},module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader']},{test: /\.less$/,use: ['style-loader', 'css-loader','less-loader']},{//处理图片资源(样式中的图片资源,html中的是处理不了的)test: /\.(jpg|png|gif)$/,loader: 'url-loader', //通过es6module解析options: {limit: 8 * 1024,name: '[name].[hash:10].[ext]',//关闭es6模块化,开启commonjs模块化esModule: false,outputPath:'img'}},{//处理html中的img资源test: /\.html$/,loader: 'html-loader',options: {esModule: false}},{//处理其他资源exclude: /\.(html|js|css|less|jpg|png|gif)$/,loader: 'file-loader',  //url-loader是基于file-loader封装的,多一些压缩功能,比如讲图片转成base64格式options: {name: '[name].[hash:10].[ext]',outputPath:'media'}}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html',//inject: 'head',scriptLoading: 'blocking',title:'Hot Module Replacement'}),],mode: 'development',target: 'web',devServer: {contentBase: './dist',//启动gzip压缩compress: true,//端口号port: 8888,//首次运行自动打开浏览器open: 'Chrome',// 开启HMR功能//当修改了webpack配置,新配置要想生效必须重启webpack服务hot: true}};

source-map

定义

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

作用

  • 一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度

使用方法

  1. devtool:'source-map' 基本配置

     devtool: 'source-map'  //生产环境选择devtool: 'eval-source-map' //开发环境选择
    
  2. 几个可选参数:
        [inline-|hidden|eval-][nosources-][cheap-[module-]]source-map
    
  3. 内联和外部
    • 外部生成了 map 文件
    • 内联在 bundle.js 文件中
    • 内联构建速度更快
  • source-map 外部

    • 错误代码的准确信息 和 源代码的错误位置
  • inline-source-map 内联
    • 只生成一个内联source-map
    • 错误代码的准确信息 和 源代码的错误位置
  • hidden-source-map 外部
    • 错误代码错误原因,但是没有错误位置
    • 不能追踪源代码错误,只能看到构建后代码的错误位置
  • eval-source-map 内联
    • 每个文件后面追加一个source-map 在eval函数中
    • 错误代码的准确信息 和 源代码的错误位置,多一个hash值
  • nosources-source-map 外部
    • 错误代码的准确信息,但是没有任何源代码信息
  • cheap-source-map 外部
    • 错误代码的准确信息 和 源代码的错误位置
    • 只能精确到行,不能精确到列
  • cheap-module-source-map 外部
    • 错误代码的准确信息 和 源代码的错误位置
    • module会将loader的source map加入
  • 开发环境:速度快,调试更友好
  • 速度快eval>inline>cheap>...
  • eval-cheap-source-map 第一
  • eval-source-map
  • 调试友好
  • source-map 第一
  • cheap-module-source-map
  • cheap-source-map
  • 又快又好 – > eval-source-map / eval-cheap-module-source-map

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

代码实现

 const { resolve } = require('path');const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {//入口文件entry:['./src/js/index.js','./src/index.html'],//出口output: {//输出的文件名filename: 'js/bundle.js',//输出的路径path: resolve(__dirname, 'dist'),clean:true //清理旧文件},module: {rules: [{test: /\.css$/,use: ['style-loader', 'css-loader']},{test: /\.less$/,use: ['style-loader', 'css-loader','less-loader']},{//处理图片资源(样式中的图片资源,html中的是处理不了的)test: /\.(jpg|png|gif)$/,loader: 'url-loader', //通过es6module解析options: {limit: 8 * 1024,name: '[name].[hash:10].[ext]',//关闭es6模块化,开启commonjs模块化esModule: false,outputPath:'img'}},{//处理html中的img资源test: /\.html$/,loader: 'html-loader',options: {esModule: false}},{//处理其他资源exclude: /\.(html|js|css|less|jpg|png|gif)$/,loader: 'file-loader',  //url-loader是基于file-loader封装的,多一些压缩功能,比如讲图片转成base64格式options: {name: '[name].[hash:10].[ext]',outputPath:'media'}}]},plugins: [new HtmlWebpackPlugin({template: './src/index.html',//inject: 'head',scriptLoading: 'blocking'}),],mode: 'development',target: 'web',devServer: {contentBase: './dist',//启动gzip压缩compress: true,//端口号port: 8888,//首次运行自动打开浏览器open: 'Chrome',// 开启HMR功能//当修改了webpack配置,新配置要想生效必须重启webpack服务hot: true},//devtool: 'source-map'  //生产环境选择devtool: 'eval-source-map' //开发环境选择};

oneOf

定义

  • 以下 loader 只会匹配一个

作用

  • 优化生产环境打包构建速度

使用方法

  1. 在众多 loader 外嵌套一层

         oneOf: [{//css兼容性处理test: /\.css$/,use: [...commonCssloader],},//...]
    

要点记录

  1. oneOf 里不能有两个配置处理同一种类型文件

代码实现

 /*** oneOf:优化生产环境打包构建速度*///绝对路径解析方法const { resolve } = require("path");//提取css成单独文件插件const MiniCssExtractPlugin = require('mini-css-extract-plugin')//最新压缩css插件const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');//手动添加webpack内部js压缩器const TerserWebpackPlugin = require('terser-webpack-plugin');//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境process.env.NODE_ENV = 'production'//复用loaderconst commonCssloader = [MiniCssExtractPlugin.loader,//提取css为单独文件'css-loader',{//兼容性处理 还需要在package.json中定义browserslistloader: 'postcss-loader',options: {postcssOptions: {ident: 'postcss',plugins: ['postcss-preset-env']}}}]module.exports = {entry: './src/js/index.js',output: {filename: 'js/bundle.js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},//压缩cssoptimization: {minimize: true,minimizer: [new TerserWebpackPlugin(),new CssMinimizerPlugin()]},module: {rules: [/***  正常来讲,一个文件只能被一个loader处理*  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序*  在loader中设置enforce:'pre',最先执行*/{//优化生产环境打包构建速度//以下loader只会匹配一个//注意:这里不能有两个配置处理同一种类型文件oneOf: [{//css兼容性处理test: /\.css$/,use: [...commonCssloader],},{//less兼容性处理test: /\.less$/,use: [...commonCssloader,//use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间'less-loader'//将less转成css文件],},{//js兼容性处理test: /\.js$/,exclude: /node_modules/,loader:'babel-loader' //配置在.babelrc文件中},{//图片处理test: /\.(jpg|png|gif)$/,loader: 'url-loader',options: {limit: 8 * 1024,//对8kb以下的图片进行base64处理name: '[name].[hash:8].[ext]',//对处理后的图片重命名outputPath: 'img', //设置处理后的图片路径publicPath: './', //指定打包后的css图片的基础路径,esModule:false //关闭es6模块化}},{//处理html中的图片问题test: /\.html$/,loader: 'html-loader',options: {esModule:false}},// 打包iconfont字体图标,和打包图片类似{test:/\.ttf$/,use: {loader: 'file-loader',options: {esModule: false, // 新版本中esModule默认为true,会导致文件的地址变为[object Module],因此这里设置为falsename: '[name]_[hash:6].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀]outputPath: 'fonts/',       // 文件存储路径(output.path + 值)(物理路径, 存储路径)publicPath:'../fonts' ,     // 负责输出目录, 即打包后的写在磁盘的位置// 输出解析文件的目录,url 相对于 HTML 页面(index.html所在文件夹的绝对路径 + 值)(文件引用路径就是看这个)// 如果output设置了publicPath, options也设置了publicPath,优先以options的publicPath为主// 是对页面引入资源的补充,比如img标签引入或者css引入等.// 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件// 一般只设置output的publicPath,方便统一管理limit: 1024        // 限制当文件小于1KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于1KB,则打包文件到指定目录,避免js过大}}},{//处理其他文件exclude: /\.(js|css|less|html|jpg|png|gif|ttf)$/,loader: 'file-loader',options: {name: '[name].[hash:8].[ext]',outputPath:'media'},// type: 'asset/resource',// generator: {//     filename: 'media/[name].[hash:6].[ext]'// }},]}]},devtool: 'source-map',//错误追踪plugins: [//提取css为单独文件new MiniCssExtractPlugin({filename:'css/built.css'}),//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式//html压缩mimify: {//移除空格collaspeWhitespace: true,//移除注释removeComments:true}})],//mode为production,js就自动压缩了mode:'production'}

缓存

作用

  • babel缓存

    • 让第二次打包构建速度更快
  • 文件缓存
    • 让代码上线运行缓存更好使用 上线代码性能优化

使用方法

  1. 开启 babel 缓存

      {//js兼容性处理test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader', //配置在.babelrc文件中options: {//开启babel缓存,第二次构建时会读取之前的缓存//问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。cacheDirectory:true }}
    
  2. 添加 contenthash
     output: {filename: 'js/bundle.[contenthash:10].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},plugins: [//提取css为单独文件new MiniCssExtractPlugin({filename:'css/built.[contenthash:10].css'}),}
    
  3. 创建临时服务器 新建server.js文件 启动指令 node server.js
     /*** 服务器代码* 启动指令 node server.js* 使用nodemon server.js 需要全局安装nodemon npm i nodemon -g*/const express = require('express')const app = express();app.use(express.static('dist', { maxAge: 1000 * 3600 }));app.listen(3000);
  4. 打包之后,启动服务器,在浏览器中查看,network,刷新就能看到,后面是通过读取缓存内容显示的,速度也会更快

要点记录

  1. babel缓存
  • babel 处理后的资源缓存起来(哪里的 js 改变就更新哪里,其他 js 还是用之前缓存的资源),让第二次打包构建速度更快
  • 因为 js 文件最多 编译过程 类似 HMR 功能,但是生产环境不能用HMR功能
  • 所以在生产环境下 开启 babel缓存 ,第二次构建时,会读取之前的缓存
  • "cacheDirectory":true
  • 问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。
  • 解决:使用 hash 命名,通过更换文件名来判断哪些文件需要更新
  1. 文件缓存
  • hash :每次 webpack 构建时会生成一个唯一的 hash
  • 问题:因为 jscss 同时使用一个 hash 值。如果重新打包,会导致所有的缓存失效。但是我可能是只改动了一个文件
  • chunkhash:根据 chunk 生成的 hash 值,如果打包来源于同一个 chunk ,那么 hash 值就一样
  • 问题:jscsshash 值还是一样的,因为 css 是在 js 中被引入的,所以同属于一个 chunk
  • contenthash:根据文件的内容生成 hash 值,不同文件的 hash 值一定不一样

代码实现

 //绝对路径解析方法const { resolve } = require("path");//提取css成单独文件插件const MiniCssExtractPlugin = require('mini-css-extract-plugin')//最新压缩css插件const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');//手动添加webpack内部js压缩器const TerserWebpackPlugin = require('terser-webpack-plugin');//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境process.env.NODE_ENV = 'production'//复用loaderconst commonCssloader = [MiniCssExtractPlugin.loader,//提取css为单独文件'css-loader',{//兼容性处理 还需要在package.json中定义browserslistloader: 'postcss-loader',options: {postcssOptions: {ident: 'postcss',plugins: ['postcss-preset-env']}}}]module.exports = {entry: './src/js/index.js',output: {filename: 'js/bundle.[contenthash:10].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},//压缩cssoptimization: {minimize: true,minimizer: [new TerserWebpackPlugin(),new CssMinimizerPlugin()]},module: {rules: [/***  正常来讲,一个文件只能被一个loader处理*  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序*  在loader中设置enforce:'pre',最先执行*/{//优化生产环境打包构建速度//以下loader只会匹配一个//注意:这里不能有两个配置处理同一种类型文件oneOf: [{//css兼容性处理test: /\.css$/,use: [...commonCssloader],},{//less兼容性处理test: /\.less$/,use: [...commonCssloader,//use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间'less-loader'//将less转成css文件],},{//js兼容性处理test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader', //配置在.babelrc文件中options: {//开启babel缓存,第二次构建时会读取之前的缓存//问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。cacheDirectory:true }},{//图片处理test: /\.(jpg|png|gif)$/,loader: 'url-loader',options: {limit: 8 * 1024,//对8kb以下的图片进行base64处理name: '[name].[hash:8].[ext]',//对处理后的图片重命名outputPath: 'img', //设置处理后的图片路径publicPath: './', //指定打包后的css图片的基础路径,esModule:false //关闭es6模块化}},{//处理html中的图片问题test: /\.html$/,loader: 'html-loader',options: {esModule:false}},// 打包iconfont字体图标,和打包图片类似{test:/\.ttf$/,use: {loader: 'file-loader',options: {esModule: false, // 新版本中esModule默认为true,会导致文件的地址变为[object Module],因此这里设置为falsename: '[name]_[hash:6].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀]outputPath: 'fonts/',       // 文件存储路径(output.path + 值)(物理路径, 存储路径)publicPath:'../fonts' ,     // 负责输出目录, 即打包后的写在磁盘的位置// 输出解析文件的目录,url 相对于 HTML 页面(index.html所在文件夹的绝对路径 + 值)(文件引用路径就是看这个)// 如果output设置了publicPath, options也设置了publicPath,优先以options的publicPath为主// 是对页面引入资源的补充,比如img标签引入或者css引入等.// 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件// 一般只设置output的publicPath,方便统一管理limit: 1024                 // 限制当文件小于1KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于1KB,则打包文件到指定目录,避免js过大}}},{//处理其他文件exclude: /\.(js|css|less|html|jpg|png|gif|ttf)$/,loader: 'file-loader',options: {name: '[name].[hash:8].[ext]',outputPath:'media'},// type: 'asset/resource',// generator: {//     filename: 'media/[name].[hash:6].[ext]'// }},]}]},devtool: 'source-map',//错误追踪plugins: [//提取css为单独文件new MiniCssExtractPlugin({filename:'css/built.[contenthash:10].css'}),//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式//html压缩mimify: {//移除空格collaspeWhitespace: true,//移除注释removeComments:true}})],//mode为production,js就自动压缩了mode: 'production'}

tree shaking

定义

  • 将应用程序想象成一棵树。实际使用的源代码和库表示树的绿色活叶。死代码表示秋天被树木消耗的褐色枯叶,为了摆脱枯叶,必须摇晃树,使它们掉落
  • 官方文档

作用

  • tree shaking:去除无用代码,

使用方法

  1. 使用ES2015模块语法(即importexport
  2. 开启 production 环境 (webpack4 还必须使用 es6 模块化)
  3. package.json 中配置无副作用的文件
     {"name":"your-project","sideEffects": ["*.css","*.less","./src/xxx"],          }
    

要点记录

  1. “副作用”:在导入时执行特殊行为的代码,而不公开一个或多个导出。
  • "sideEffects":false

    • 所有代码都没有副作用(都可以进行tree shaking)问题:可能会把css文件删掉
  • "sideEffects": true所有文件都有副作用,
    • 全都不可 tree-shaking
  • "sideEffects": ["*.css","*.less"]
    • 除了css,less文件有副作用,所有其他文件都可以 tree-shaking,但会保留这些文件
  1. "sideEffects"类似于,/*#__PURE__*/ 但在模块级别而不是语句级别。
  2. 通过使用 /*#__PURE__*/ 注释,可以告诉webpack函数调用是无副作用的(纯净的)。可以将其放在函数调用之前,以将其标记为无副作用。传递给函数的参数不会被注释标记,可能需要单独标记。当未使用变量的变量声明中的初始值被视为无副作用(纯净)时,它将被标记为无效代码,不被 minimizer 执行并丢弃, optimization.innerGraph 设置为 true 的时候启用。
     /*#__PURE__*/ double(55);
    

代码实现

 //绝对路径解析方法const { resolve } = require("path");//提取css成单独文件插件const MiniCssExtractPlugin = require('mini-css-extract-plugin')//最新压缩css插件const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');//手动添加webpack内部js压缩器const TerserWebpackPlugin = require('terser-webpack-plugin');//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境process.env.NODE_ENV = 'production'//复用loaderconst commonCssloader = [MiniCssExtractPlugin.loader,//提取css为单独文件'css-loader',{//兼容性处理 还需要在package.json中定义browserslistloader: 'postcss-loader',options: {postcssOptions: {ident: 'postcss',plugins: ['postcss-preset-env']}}}]module.exports = {entry: './src/js/index.js',output: {filename: 'js/bundle.[contenthash:10].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},//压缩cssoptimization: {minimize: true,minimizer: [new TerserWebpackPlugin(),new CssMinimizerPlugin()]},module: {rules: [{oneOf: [{//css兼容性处理test: /\.css$/,use: [...commonCssloader],},{//less兼容性处理test: /\.less$/,use: [...commonCssloader,//use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间'less-loader'//将less转成css文件],},{//js兼容性处理test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader', //配置在.babelrc文件中options: {//开启babel缓存,第二次构建时会读取之前的缓存//问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。cacheDirectory:true }},{//图片处理test: /\.(jpg|png|gif)$/,loader: 'url-loader',options: {limit: 8 * 1024,//对8kb以下的图片进行base64处理name: '[name].[hash:8].[ext]',//对处理后的图片重命名outputPath: 'img', //设置处理后的图片路径publicPath: './', //指定打包后的css图片的基础路径,esModule:false //关闭es6模块化}},{//处理html中的图片问题test: /\.html$/,loader: 'html-loader',options: {esModule:false}},// 打包iconfont字体图标,和打包图片类似{test:/\.ttf$/,use: {loader: 'file-loader',options: {esModule: false, // 新版本中esModule默认为true,会导致文件的地址变为[object Module],因此这里设置为falsename: '[name]_[hash:6].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀]outputPath: 'fonts/',       // 文件存储路径(output.path + 值)(物理路径, 存储路径)publicPath:'../fonts' ,     // 负责输出目录, 即打包后的写在磁盘的位置// 输出解析文件的目录,url 相对于 HTML 页面(index.html所在文件夹的绝对路径 + 值)(文件引用路径就是看这个)// 如果output设置了publicPath, options也设置了publicPath,优先以options的publicPath为主// 是对页面引入资源的补充,比如img标签引入或者css引入等.// 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件// 一般只设置output的publicPath,方便统一管理limit: 1024                 // 限制当文件小于1KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于1KB,则打包文件到指定目录,避免js过大}}},{//处理其他文件exclude: /\.(js|css|less|html|jpg|png|gif|ttf)$/,loader: 'file-loader',options: {name: '[name].[hash:8].[ext]',outputPath:'media'},// type: 'asset/resource',// generator: {//     filename: 'media/[name].[hash:6].[ext]'// }},]}]},devtool: 'source-map',//错误追踪plugins: [//提取css为单独文件new MiniCssExtractPlugin({filename:'css/built.[contenthash:10].css'}),//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式//html压缩mimify: {//移除空格collaspeWhitespace: true,//移除注释removeComments:true}})],//mode为production,js就自动压缩了mode: 'production'}

code split

  • 可以将代码分成多个 bundles ,然后可以按需或并行加载,可以用于实现更小的 bundle 和控制资源加载优先级
  • 官方文档

entry points(入口起点)

定义
  • 使用 entry 配置手动地分离代码
  • 官方文档
使用方法
  1. 将入口设置为一个对象
  2. 更改输出文件名
       //单入口//entry: './src/js/index.js',entry: {index: './src/index.js',another: './src/another-module.js',},output: {//filename: 'main.js',filename: '[name].bundle.js'},
要点记录
  1. 多入口:一个入口 ,输出就有一个 bundle
  2. 问题:如果入口 chunk 之间包含一些重复的模块,那些重复模块都会被引入到各个 bundle 中。
  3. 这种方法不够灵活,并且不能动态地将核心应用程序逻辑中的代码拆分出来。
代码实现
 /*** code split entry point* 入口为一个对象* entry:{}*///绝对路径解析方法const { resolve } = require("path");//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {//单入口//entry: './src/js/index.js',entry: {//多入口:一个入口 --> 输出就有一个bundleindex: './src/js/index.js',add: './src/js/add.js'},output: {//[name]:取文件名filename: 'js/[name].[contenthash:10].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},plugins: [//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式})],mode: 'development',}

prevent duplication(防止重复)

定义
  • 使用 Entry dependencies 或者 SplitChunksPlugin 去重和分离 chunk
  • 官方文档
使用方法
Entry dependencies
  1. 配置 dependOn option 选项然后再加上optimization.runtimeChunk: 'single',否则会出问题,这样可以在多个 chunk 之间共享模块

    module.exports = {mode: 'development',entry: {index: {import: './src/index.js',dependOn: 'shared',},another: {import: './src/another-module.js',dependOn: 'shared',},shared: 'lodash',},output: {filename: '[name].bundle.js'},optimization: {runtimeChunk: 'single',},
    };
    

    除了生成 shared.bundle.jsindex.bundle.jsanother.bundle.js 之外,还生成了一个 runtime.bundle.js 文件

SplitChunksPlugin
  1. SplitChunksPlugin 插件可以将公共的依赖模块提取到现有的入口 chunk 中,或者提取到一个新生成的 chunk 。让我们使用这个插件,将在此之前的示例中重复的 lodash 模块移除

       module.exports = {mode: 'development',entry: {index: './src/index.js',another: './src/another-module.js',},output: {filename: '[name].bundle.js',path: path.resolve(__dirname, 'dist'),},optimization: {splitChunks: {chunks: 'all',},},};
    

    有了 optimization.splitChunks 配置选项后,我们现在应该看到从index.bundle.js 中删除了重复的依赖项 another.bundle.js。插件将lodash 分离到单独的块

要点记录
  1. 尽管可以在 webpack 中允许每个页面使用多入口,应确保避免使用多入口的入口: entry: { page: ['./analytics', './app'] } 。如此,在使用 async 脚本标签时,会有更好的优化以及一致的执行顺序
  2. index.js 文件这样引入 jquery
     import $ from 'jquery';console.log($);
    

    直接打包会将 jqueryindex.js 打包成一个文件,加上 splitChunks.chunks为all ,就能将引入的第三方库,单独打包出来,还能分析多入口 chunk 中有没有公共文件(>30kb),有就单独打包

代码实现
 /*** prevent duplication(防止重复)*///绝对路径解析方法const { resolve } = require("path");//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {//单入口entry: './src/js/index.js',// entry: {//     index: './src/js/index.js',//     add: './src/js/add.js'// },output: {//[name]:取文件名filename: 'js/[name].[contenthash:10].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},optimization: {/*** 单入口只有1,多入口1、2都有* 1. 可以将node_modules中代码单独打包成一个chunk最终输出* 2. 自动分析多入口chunk中有没有公共的文件(>30kb),如果有会单独打包成一个chunk*/splitChunks: {chunks:'all'}},plugins: [//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式})],mode: 'development',}

import(动态引入)

定义
  • 通过模块的内联函数调用来分离代码
  • 官方文档
    • import() function(string path):Promise 动态加载模块。详细
    • require.ensure() 特定于webpack 详细
使用方法
  1. 通过 js 代码,让某个文件被单独打包成一个 chunk
  • import 动态导入语法:能将某个文件单独打包

     /*** 通过js代码,让某个文件被单独打包成一个chunk* import动态导入语法:能将某个文件单独打包*/import(/* webpackChunkName:'add' */'./add').then(({ mul, count }) => {console.log('add文件加载成功');console.log("3+9=" + mul(3, 9));console.log("3-9="+count(3,9));}).catch(() => {console.log('文件加载失败');})
要点记录
  1. 语法

       import(/* webpackChunkName:'test' */'./test')
    
代码实现
 /*** code split* 单入口,import()动态引入*///绝对路径解析方法const { resolve } = require("path");//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {//单入口entry: './src/js/index.js',output: {//[name]:取文件名filename: 'js/[name].[contenthash:5].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},plugins: [//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式})],mode: 'development',}

lary loading

定义

  • 懒加载 前提:进行代码分割,当文件需要使用时才加载
  • 官方文档
  • 预加载 prefetch:会在使用之前,提前加载 js 文件 使用慎之又慎。详细
    • 正常加载可以认为是并行加载(同一时间加载多个文件)
    • 预加载 :等其他资源加载完毕,浏览器空闲了,再偷偷加载资源

使用方法

  1. 通过 js 代码,让某个文件被单独打包成一个 chunk
    import动态导入语法:能将某个文件单独打包

       document.getElementById('btn').onclick = function () {import(/* webpackChunkName:'add',webpackPrefetch:true */'./add').then(({ mul }) => {console.log(mul(4, 5));})}
    

要点记录

  1. 增加一个交互,当用户单击按钮的时候用 console 打印一些文字,但是会等到第一次交互的时候再加载那个代码块(print.js

代码实现

 /*** lary 懒加载*///绝对路径解析方法const { resolve } = require("path");//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {//单入口entry: './src/js/index.js',output: {//[name]:取文件名filename: 'js/[name].[contenthash:10].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},optimization: {splitChunks: {chunks:'all'}},plugins: [//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式//html压缩mimify: {//移除空格collaspeWhitespace: true,//移除注释removeComments:true}})],//mode为production,js就自动压缩了mode: 'production',}

PWA

定义

  • 渐进式Web应用程序(或 PWA )是可提供与本机应用程序相似的体验的 Web 应用程序。有很多事情可以促成这一点。在这些功能中,最重要的是使应用程序能够在离线状态下运行的能力,这是通过使用称为 Service Workers 的网络技术来实现的
  • 官方文档

使用方法

  1. 安装插件

     npm i workbox-webpack-plugin -D
    
  2. webpack.config.js中添加
      new WorkboxWebpackPlugin.GenerateSW({/*** 1. 帮助serviceworker快速启动* 2. 删除旧的 serviceworker* * 生成一个 serviceworker 配置文件 index.js中注册*/clientsClaim: true,skipWaiting:true})
    
  3. index.js中注册serviceWorker 处理兼容性问题
      if ('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/service-worker.js').then(() => {console.log('sw注册成功了');}).catch(() => {console.log('sw注册失败了');})})}
    
  4. 安装
        npm i serve -g
    
  5. 启动服务器,将 dist 目录下所有资源作为静态资源暴露出去 把网络设置为离线之后就可以在 application 中查看 serviceworker 中的文件了,使得网站可以离线访问
     serve -s dist
    

要点记录

  1. serviceworker 代码必须运行在服务器上

代码实现

 /*** PWA:渐进式网络开发应用程序(离线可访问)* workbox --> workbox-webpack-plugin*/// workbox 下载插件const WorkboxWebpackPlugin =require('workbox-webpack-plugin')//绝对路径解析方法const { resolve } = require("path");//提取css成单独文件插件const MiniCssExtractPlugin = require('mini-css-extract-plugin')//最新压缩css插件const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');//手动添加webpack内部js压缩器const TerserWebpackPlugin = require('terser-webpack-plugin');//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境process.env.NODE_ENV = 'production'//复用loaderconst commonCssloader = [MiniCssExtractPlugin.loader,//提取css为单独文件'css-loader',{//兼容性处理 还需要在package.json中定义browserslistloader: 'postcss-loader',options: {postcssOptions: {ident: 'postcss',plugins: ['postcss-preset-env']}}}]module.exports = {entry: './src/js/index.js',output: {filename: 'js/bundle.[contenthash:10].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},//压缩cssoptimization: {minimize: true,minimizer: [new TerserWebpackPlugin(),new CssMinimizerPlugin()]},module: {rules: [/***  正常来讲,一个文件只能被一个loader处理*  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序*  在loader中设置enforce:'pre',最先执行*/{//优化生产环境打包构建速度//以下loader只会匹配一个//注意:这里不能有两个配置处理同一种类型文件oneOf: [{//css兼容性处理test: /\.css$/,use: [...commonCssloader],},{//less兼容性处理test: /\.less$/,use: [...commonCssloader,//use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间'less-loader'//将less转成css文件],},{//js兼容性处理test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader', //配置在.babelrc文件中options: {//开启babel缓存,第二次构建时会读取之前的缓存//问题:当文件名没有发生变化的时候,同名文件都是走缓存。会导致修改内容与实际展示内容不一致。cacheDirectory:true }},{//图片处理test: /\.(jpg|png|gif)$/,loader: 'url-loader',options: {limit: 8 * 1024,//对8kb以下的图片进行base64处理name: '[name].[hash:8].[ext]',//对处理后的图片重命名outputPath: 'img/', //设置处理后的图片路径publicPath: './img', //指定打包后的css图片的基础路径,esModule:false //关闭es6模块化}},{//处理html中的图片问题test: /\.html$/,loader: 'html-loader',options: {esModule: false}},// 打包iconfont字体图标,和打包图片类似{test:/\.ttf$/,loader: 'file-loader',options: {esModule: false, // 新版本中esModule默认为true,会导致文件的地址变为[object Module],因此这里设置为falsename: '[name]_[hash:6].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀]outputPath: 'fonts/',       // 文件存储路径(output.path + 值)(物理路径, 存储路径)publicPath:'../fonts' ,     // 负责输出目录, 即打包后的写在磁盘的位置// 输出解析文件的目录,url 相对于 HTML 页面(index.html所在文件夹的绝对路径 + 值)(文件引用路径就是看这个)// 如果output设置了publicPath, options也设置了publicPath,优先以options的publicPath为主// 是对页面引入资源的补充,比如img标签引入或者css引入等.// 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件// 一般只设置output的publicPath,方便统一管理limit: 1024                 // 限制当文件小于1KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于1KB,则打包文件到指定目录,避免js过大}},{//处理其他文件exclude: /\.(js|css|less|html|jpg|png|gif)$/,loader: 'file-loader',options: {// esModule: false,name: '[name].[hash:8].[ext]',outputPath: 'media/',publicPath:'../media'},// type: 'asset/resource',// generator: {//     filename: 'media/[name].[hash:6].[ext]'// }},]}]},plugins: [//提取css为单独文件new MiniCssExtractPlugin({filename:'css/built.[contenthash:10].css'}),//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式//html压缩mimify: {//移除空格collaspeWhitespace: true,//移除注释removeComments:true}}),new WorkboxWebpackPlugin.GenerateSW({/*** 1. 帮助serviceworker快速启动* 2. 删除旧的 serviceworker* * 生成一个 serviceworker 配置文件 index.js中注册*/clientsClaim: true,skipWaiting:true})],//mode为production,js就自动压缩了mode: 'production',devtool:'source-map'}

多进程打包

定义

  • 在大项目中使用 thread-loader ,提升构建速度
  • 官方文档

使用方法

  1. 安装插件

     npm i thread-loader -D
    
  2. 开启多进程打包,在 babel-loader 前面添加,可以在 options 中进行配置
     {loader: 'thread-loader',// options: {//     workers:2 // 产生的工作线程的数量,默认为(cpu数量- 1)或当require('os').cpus()未定义时,返回1// }},
    

要点记录

  1. js 一般比较多,一般给 babel-loader 用,工作时间最长的 loader,所以用 thread-loader 优化
  2. 使用了这个 loader之后:
    • loaders 不能发出文件
    • loaders 不能使用自定义loader API(即通过插件)
    • loaders 无法访问 webpack options
    • 项目较大,打包较慢,开启多进程能提高速度
    • 项目较少,打包很快,开启多进程会降低速度,进程启动大概为600ms,进程通信也有开销

代码实现

 /*** 多进程打包*/// workbox 下载插件const WorkboxWebpackPlugin =require('workbox-webpack-plugin')//绝对路径解析方法const { resolve } = require('path');//提取css成单独文件插件const MiniCssExtractPlugin = require('mini-css-extract-plugin')//最新压缩css插件const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');//手动添加webpack内部js压缩器const TerserWebpackPlugin = require('terser-webpack-plugin');//对html文件处理const HtmlWebpackPlugin = require('html-webpack-plugin');//默认使用生产环境,定义nodejs环境变量:决定使用browserslist的哪个环境process.env.NODE_ENV = 'production'//复用loaderconst commonCssloader = [MiniCssExtractPlugin.loader,//提取css为单独文件'css-loader',{//兼容性处理 还需要在package.json中定义browserslistloader: 'postcss-loader',options: {postcssOptions: {ident: 'postcss',plugins: ['postcss-preset-env']}}}]module.exports = {entry: './src/js/index.js',output: {filename: 'js/bundle.[contenthash:10].js',path:resolve(__dirname,'dist'),clean: true,publicPath:'./'},//压缩cssoptimization: {minimize: true,minimizer: [new TerserWebpackPlugin(),new CssMinimizerPlugin()]},module: {rules: [/***  正常来讲,一个文件只能被一个loader处理*  当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序*  在loader中设置enforce:'pre',最先执行*/{//优化生产环境打包构建速度//以下loader只会匹配一个//注意:这里不能有两个配置处理同一种类型文件oneOf: [{//css兼容性处理test: /\.css$/,use: [...commonCssloader],},{//less兼容性处理test: /\.less$/,use: [...commonCssloader,//use中loader执行从下往上,必须把这个处理放在css-loader与less-loader之间'less-loader'//将less转成css文件],},{//js兼容性处理test: /\.js$/,exclude: /node_modules/,use: [/*** 开启多进程打包* 进程启动大概为600ms,进程通信也有开销* 只有工作消耗时间比较长,才需要多进程打包* js一般比较多,工作时间最长的loader,所以用thread-loader优化*/{loader: 'thread-loader',options: {workers:2 //进程2个 ,产生的工作线程的数量,默认为(cpu数量- 1)CPU核数减一}},{loader: 'babel-loader', //配置在.babelrc文件中options: {//开启babel缓存cacheDirectory:true }}]},{//图片处理test: /\.(jpg|png|gif)$/,loader: 'url-loader',options: {limit: 8 * 1024,//对8kb以下的图片进行base64处理name: '[name].[hash:8].[ext]',//对处理后的图片重命名outputPath: 'img/', //设置处理后的图片路径publicPath: './img', //指定打包后的css图片的基础路径,esModule:false //关闭es6模块化}},{//处理html中的图片问题test: /\.html$/,loader: 'html-loader',options: {esModule:false}},{//处理其他文件exclude: /\.(js|css|less|html|jpg|png|gif)$/,loader: 'file-loader',options: {name: '[name].[hash:8].[ext]',outputPath: 'media/',publicPath:'../media'},// type: 'asset/resource',// generator: {//     filename: 'media/[name].[hash:6].[ext]'// }},]}]},plugins: [//提取css为单独文件new MiniCssExtractPlugin({filename:'css/built.[contenthash:10].css'}),//对html文件处理new HtmlWebpackPlugin({template: './src/index.html',scriptLoading: 'blocking',//去除script defer模式//html压缩mimify: {//移除空格collaspeWhitespace: true,//移除注释removeComments:true}}),new WorkboxWebpackPlugin.GenerateSW({/*** 1. 帮助serviceworker快速启动* 2. 删除旧的 serviceworker* * 生成一个 serviceworker 配置文件 index.js中注册*/clientsClaim: true,skipWaiting:true})],//mode为production,js就自动压缩了mode: 'production',devtool:'source-map'}

external

定义

  • Externals 配置项用来告诉 Webpack 要构建的代码中使用了哪些不用被打包的模块,也就是说这些模版是外部环境提供的,Webpack 在打包时可以忽略它们
  • 官方文档

使用方法

  1. 在module.exports中添加,要排除的包名

     externals: {//拒绝jQuery被打包进来 在html界面通过script标签引入cdn链接jquery:'jQuery'}
    
  2. 在html界面通过script标签引入cdn链接
      <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
    

要点记录

  1. cdn boostrapcdn开源网站,优化 webpack 打包
  2. external 可以防止框架的二次引用

代码实现

 const { resolve } = require('path');const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/js/index.js',output: {filename: 'js/bundle.js',path: resolve(__dirname, 'dist')},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})],mode: 'production',externals: {//拒绝jQuery被打包进来 在html界面通过script标签引入cdn链接jquery:'jQuery'}};

写在后面

优化配置,这里终于告一段落,学习的过程中有很多都已经变化了,所以附了很多官方文档的链接,还是要结合最新的文档配合学习。
未选择的路,心里永远会有一个设想,如果当初选择了另一条路会怎样,其实无论是什么样子,总不会是自己在这种情境下期待的样子,当你身处局中时,你的选择改变不了未来的,我们只能走一条路,在踏上的那一刻,就是一条全新的路了,未来因此刻的选择而变化,过去的结点没有办法回转。

webpack5 入门学习笔记(四)性能优化相关推荐

  1. ROS中的roslaunch命令和launch文件(ROS入门学习笔记四)

    ROS中的基本对象和概念学习笔记(ROS入门学习笔记一) ROS中创建工作区和包(ROS入门学习笔记二) ROS功能包中CMakeLists.txt的说明(ROS入门学习笔记三) 1.roslaunc ...

  2. Android八大模块进阶学习笔记(性能优化、百大框架、高级UI、Flutter、Kotlin...)

    今年来,Android开发行业的就业形势愈加严峻,无论刚刚入门Android学习没有头绪的.还是开发多年想要突破薪资范畴的,都需要跳出编码和业务的局限,学会选型.扩展, 提升编程思维,建立良好的职业规 ...

  3. 《南溪的目标检测学习笔记》——性能优化的学习笔记

    介绍 性能优化有两种方式: 理论分析 实验测试 1 理论分析 关于模型的性能分析,请参考博文<Roofline Model与深度学习模型的性能分析 (by Michael Yuan)>:

  4. 动态博弈、威胁与承诺(博弈论入门学习笔记四)

    0 动态博弈 动态博弈:行动有先后顺序,不同的参与人在不同时点行动,先行动者的选择影响后行动者的选择空间,后行动者可以观察到先行动者做了什么选择.例如下棋.消费者和商家讨价还价.谈婚论嫁.企业之间的价 ...

  5. 斋藤康毅-深度学习入门 学习笔记四

    ch 神经网络的学习 损失函数 1.1 均方误差 import numpy as npdef mean_squared_error(y, t):return 0.5 * np.sum((y - t) ...

  6. 代理重加密-入门学习笔记(四)

    代理重加密(PRE)(重密码学!) 原文: https://blog.csdn.net/Black_BearB/article/details/81228030 1.基本思想-流程结算 在云计算中,云 ...

  7. UE4入门学习笔记——纪念学习虚幻引擎满一周年

    UE4入门学习笔记 前言: 今天是正式学习ue4一周年.一年前的今天,我结束了PBR流程的学习,怀揣着对游戏制作的热爱,正式开始学习ue4,继续追寻儿时的那个大厂梦.谁也没想到,一年后的今天,我会在T ...

  8. MySQL高级学习笔记(四)

    文章目录 MySQL高级学习笔记(四) 1. MySql中常用工具 1.1 mysql 1.1.1 连接选项 1.1.2 执行选项 1.2 mysqladmin 1.3 mysqlbinlog 1.4 ...

  9. 激光SLAM入门学习笔记

    激光SLAM入门学习笔记 激光SLAM入门学习笔记 一.推荐阅读书籍 二.推荐公众号.知乎.博客 1.公众号 2.知乎 3.博客 三.推荐阅读论文&代码(参考泡泡机器人) 2D激光SLAM 3 ...

  10. .net core底层入门学习笔记(十一-JIT编译器)

    .net core底层入门学习笔记(十一) 本篇开始记录JIT编译器实现 文章目录 .net core底层入门学习笔记(十一) 前言 一.JIT编译器介绍 二.JIT编译流程 1.JIT编译触发 2. ...

最新文章

  1. ionic中的后退方法
  2. Babylon.js 3.3发布:更强大的粒子系统和WebVR支持
  3. Repeater 嵌套 绑定数据,嵌套的Repeater无法绑定的问题
  4. c语言%f小数位第六位是错的,c语言中输出浮点型数据,如果不指定输出位数,%f输出几位小数?...
  5. python实现udp聊天室_python网络编程基础--socket的简介,以及使用socket来搭建一个简单的udp小程序...
  6. JavaScript一个简易枚举类型实现扑克牌
  7. JAVA Useful Program(1)
  8. excel实时获取基金信息的实现方法
  9. 智能优化算法:粒子群算法相关代码
  10. iOS 版本更新迭代
  11. ATTCK实战系列一(内网渗透入门)
  12. 虚拟机运行python_虚的解释|虚的意思|汉典“虚”字的基本解释
  13. 妙用thead封装vue组件
  14. d630 无线驱动 linux,DELL D630安装CentOS6的无线网卡驱动
  15. 最大传输单元:MTU
  16. #4【BZOJ5109】[CodePlus 2017]大吉大利,晚上吃鸡!(未完成)
  17. mongoose用模型更新不了,因为模型对象中默认带有_id会提示errmsg: “Performing an update on the path ‘_id‘ would modify the i
  18. poj 1659 Havel-hakimi定理
  19. 负载均衡、DNS、F5、反向代理、LVS、四层与七层、CDN
  20. OWASP TOP 10 漏洞指南(2021)

热门文章

  1. 保护模式下的80386及其编程03:保护虚拟地址方式
  2. 计算机财务基础知识,财务部计算机基础知识培训.ppt
  3. linux系统下面所有命令都失效了,显示bash: xxxxx: command not found...
  4. 贴片铝电容识别及型号_电路板上的贴片电容怎样核实它的型号及参数是多少
  5. 【可视化】使用PS将图片从白底换成其他底色时,如何保留头发边缘的发丝
  6. 【Photoshop】证件照换底色
  7. matlab基波有效值,基波有效值
  8. 电流测试c语言算法,真有效值的定义及其C语言算法推导
  9. phpcms v9给栏目添加自定义英文栏目名称字段图文教程
  10. c# 指定打开某个路径下的CMD_C# 插入、删除Excel分页符