webpack5 学习笔记

安装webpack 和 CLI

# webpack 5 runs on Node.js version 10.13.0+.

npm install webpack webpack-cli -g 
# yarn add webpack webpack-cli

Commands

# npx webpack 命令
build | b [option] # 编译打包
configtest | t [config-path]  # 验证可配置的webpack.config.js文件内容
info | i [option] # 输出关于系统的信息(OS、CPU、npm/yum/Node、Browsers、Packages)
init | c [option] # 初始化一个webpack的工程
server | s [option] # 运行webpack-dev-server
version | v # 输出webpack CLI的版本信息
watch | w [option] # 运行webpack 监听文件的变化

Flags

列举几个,同时还有Negated Flags, eg --no-color --no-watch

Falg/Alias Type 描述
–entry string[] 程序的入口
–config, -c string[] webpack配置文件的路径 eg ./webpack.config.js
–config-name string webpack多个配置时,选择配置
–node-env string 设置process.env.NODE_ENV
–progress string、boolean 输出编译的过程
–output-path,-o string 设置编译输出的文件目录 eg ./dist
–hot, -h boolean 热模块更新是否启用
–color boolean console上是否可用color
–json, -j string、boolean 已JSON格式输出到一个文件
–analyze boolean webpack-bundle-analyzer插件的bundle信息

--help=verbose 列出所以的参数
help --entry 具体的–entry参数

Guides

起步

配置最简单的项目

// webpack.config.js
// npx webpack --config webpack.config.js 可以直接执行 
// 或者 package.json 中script 中添加 "build": "webpack" 执行build时会默认去执行配置文件 webpack.config.js
const path = require('path')

module.exports = {
    
    
    mode: 'production',
    entry: './src/index.js',
    output: {
    
    
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
}
<!-- /dist/index.html  -->
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
</head>
<body>
    <script src="bundle.js"></script>
</body>
</html>

在编译结束后发现生成的文件会多一个.LISTENSE.text后缀的文件(webpack5 自带的terser-webpack-plugin 去压缩JS时,extractComments 属性默认true 会提取当前JS文件中的注释到.LISTENSE.text的文件中)

Asset Management

  1. Loading CSS
    使用sass(Dart Sass)时,由于异步回调的开销,默认情况下,同步编译的速度是异步编译速度的两倍。为了避免这种开销,您可以使用fibers包从同步代码路径中调用异步导入程序。node-sass不存在这种情况。
  2. Loading Images
    CSS中使用背景和图标等图像或者JS import MyImage from './image.png'时,从webpack 5开始,使用内置的Asset Modules(通过他加载的任何文件,编译时都输出到构建目录),我们也可以轻松地将其合并到我们的系统中
    html-loader 会处理同样的方式处理 <img src="./my-image.png" />
...
module: {
    
    
     rules: [
      {
    
    
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      }
     ]
   },
...
  1. Loading Fonts
	  {
    
    
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      }
  1. Loading Data
    针对 xml文件和 csv(Comma-Separated Values,逗号分隔值)文件,csv-loader/xml-loader
    yarm配置文件或者json5, yamljs/json5
	const yaml = require('yamljs')
	const json5 = require('json5')

	  {
    
    
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
    
    
        test: /\.xml$/i,
        use: ['xml-loader'],
      },
      {
    
    
        test: /\.yaml$/i,
        type: 'json',
        parser: {
    
    
            parse: yaml.parse,
        },
      },
      {
    
    
        test: /\.json5$/i,
        type: 'json',
        parser: {
    
    
            parse: json5.parse,
        },
      }

js 文件中可以import 以上文件去获取配置文件的属性

Output Management

html-webpack-plugin 将用一个新生成的文件替换我们的index.html文件

Development

mode: 'development',
devtool: 'inline-source-map', // 为了更容易跟踪错误和警告,source-map 将编译后的代码映射回原始源代码

帮助我们在更改时自动编译

  1. Watch Mode
...
	"script": {
    
    
		"watch": "webpack --watch"
	}
...

唯一的缺点:就是需要手动去刷新页面去看改变的结果
2. webpack-dev-server (常用)
npm install --save-dev webpack-dev-server

// webpack.config.js
...
devServer: {
    
    
	// 相关属性
	hot: true // HMR 热更新
}
...

http://[devServer.host]:[devServer.port]/[output.publicPath]/[output.filename]
3. webpack-dev-middleware
结合express框架,创建服务
配置文件输出中添加publicPath: '/', webpack-dev-middleware需要

// server.js
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);

// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(
  webpackDevMiddleware(compiler, {
    
    
    publicPath: config.output.publicPath,
  })
);

// Serve the files on port 3000.
app.listen(3000, function () {
    
    
  console.log('Example app listening on port 3000!\n');
});

pack.json中添加命令server: node server.js用以启动服务

Code Splitting

将代码分割成更小的bundles,按需或者并行加载这些包,正确使用对负载的时间有很大的影响
一般有三种方法拆分代码

  1. Entry Points:使用entry配置手动拆分代码
  2. Prevent Duplication:用 Entry dependencies 或SplitChunksPlugin进行重复数据删除和拆分
  3. Dynamic Imports

尽可能避免使用具有多个导入的入口点:entry:{page:[’./analytics’,’./app’]}。这将结果最好通过异步JS去优化和按顺序执行

SplitChunksPlugin 允许我们去提取公共的依赖到一个已存在的entry chunk中或者一个新的chunk中
优化配置optimization.splitChunks 就是SplitChunksPlugin 插件可选的配置

Prefetching/Preloading modules webpack4.6.0+ 支持

  1. prefetch: 资源可能在在未来的一些导航中需要
  2. preload: 当前导航将需要的资源
// 例如在点击登录后接下来需要加载登录的组件
import(/* webpackPrefetch: true */ './path/to/LoginModal.js')

preload在父级chunk开始执行;prefetch 在父chunk完成加载后开始执行
preload chunk 有中等优先级,可以立即下载;prefetch chunk 只能等浏览器空闲的时候
浏览器的支持也不同

错误的使用webpackPreload 会影响性能

Bundle Analysis
webpack-chart、webpack-visualizer、webpack-bundle-analyzer、webpack bundle optimize helper

Caching

webpack 提供了一种使用方括号括起来的字符串来替代文件名的模板方法,eg.[name]/[contenthash]

webpack提供了优化功能,可以使用optimization.runtimeChunk选项将运行时代码拆分为单独的块,将其设置为single可为所有块创建运行时共享的单个chunk。(参数是string时可选的值为all(chunks能在同步和异步chunks之间共享)、async、initial;)

将第三方库(例如lodash或react)提取到单独的vendor块中也是一个好习惯,因为与我们的本地源代码相比,第三方供应商块发生变化的可能性较小。此步骤将允许客户端从服务器请求的内容更少,以保持最新状态。通过optimization.splitChunks中的 cacheGroups去实现(
继承或覆盖splitChunks中的任何选项;但是只能在cacheGroups上配置test,priority(默认-20)和reuseExistingChunk(默认true))。

	// webpack.config.js
	optimization: {
    
    
      runtimeChunk: 'single', // 会生成一个在所有生成chunk之前共享的运行时文件 runtime.bundle.js
      splitChunks: {
    
    
       chunks: 'all',
       cacheGroups: {
    
    
         vendor: {
    
    
           test: /[\\/]node_modules[\\/]/,
           name: 'vendors',
           chunks: 'initial',
         },
         elementUI: {
    
    
            name: 'chunk-elementUI', // split elementUI into a single package
            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
            test: /[\\/]node_modules[\\/]_?element-ui(.*)/
          },
          commons: {
    
    
            name: 'chunk-commons',
            test: path.join(__dirname,'src/components'),
            minChunks: 3, 
            priority: 5,
            reuseExistingChunk: true
          }
       },
     },
    },

Authoring Libraries

// webpack.config.js
...
	output: {
    
    
		...
		library: {
    
    
			name: 'libraryCustomName',
			type: 'umd'
		}
	},
	externals: {
    
     // 当前库额外的依赖,使用权交给库的使用者
     	lodash: {
    
    
       		commonjs: 'lodash',
       		commonjs2: 'lodash',
       		amd: 'lodash',
       		root: '_',
     	},
   },
...

Environment Variables

Webpack的环境变量不同于bash和CMD.exe等操作系统shell的环境变量
可以在命令行中--env name=local 或者 --env production
VSCode 编辑器可以在项目根目录下设置.env .env.production 文件去设置不同的环境变量

Build Performance

General

无论开发还是生成都有所帮助

  1. Loaders
    在每个loader处理的时候使用include去选择实际要做处理的模块
  2. Bootstrap
    每一个loader/plugin都需要启动时间,尽量少使用
  3. Resolving
    提高解析的速度:
    • resolve.symlinks: false ;不使用npm link 等创建符号链接的操作
    • resolve.cacheWithContext: false ;用自定义的解析插件,不存在解析上下文
    • 最小化resolve.modules,resolve.extensions,resolve.mainFiles,resolve.descriptionFiles中的项目数量,因为它们增加了文件系统调用的数量
  4. DLL
    使用DllPlugin将不常更改的代码移动到单独的编译中。尽管这确实会增加构建过程的复杂性,但这将提高应用程序的编译速度
  5. Smaller = Faster
  6. Worker Pool
    thread-loader可以将昂贵的loades放到worker pool里面
  7. Persistent cache
    设置cache属性在配置文件中
  8. 自定义plugin/loader
  9. Progress plugin

开发

  • Incremental Builds
    对于许多watch的文件,这可能会导致大量的CPU负载。您可以使用watchOptions.poll增加轮询间隔
  • Compile in Memory
    webpack-dev-server、webpack-hot-middleware、webpack-dev-middleware
  • stats.toJson speed
    stats.toJson() 默认输出大量的数据,除非在增量步骤中有必要,否则请避免检索stats对象的部分。
  • Devtool
    不同的设置也是不同的性能
    大多数清楚eval-cheap-module-source-map是最好的选择
  • Avoid Production Specific Tooling
    生成环境中应该避免出现如下的TerserPlugin、[fulgash]/[chunkhash]/[contenthash]
  • Minimal Entry Chunk
    配置optimization.runtimeChunk
  • Avoid Extra Optimization Steps
    这些优化对于较小的代码库是高性能的,但是在较大的代码库中可能会很昂贵
  optimization: {
    
    
    removeAvailableModules: false,
    removeEmptyChunks: false,
    splitChunks: false,
  }
  • Output Without Path Info
  output: {
    
    
    pathinfo: false,
  }
  • Node.js Versions 8.9.10-9.11.1
    Map 和Set的性能有点下降,其他版本不影响
  • TypeScript Loader
	{
    
    
      	loader: 'ts-loader',
      	options: {
    
    
        	transpileOnly: true, // 提升编译时间
      	},
    }

生产

  • Multiple Compilations
    parallel-webpack、cache-loader 会有所帮助
  • Source Maps
    很昂贵,确定真的需要?

node-sass有一个错误,该错误阻止了Node.js线程池中的线程。想使用时设置thread-loader中workerParallelJobs:2

Tree Shaking

为了利用Tree Shaking的优势,你这必须尽心一下操作

  • 使用ES2015模块语法(import、export)
  • 添加sideEffects 在package.json中
  • 使用production模式

Lazy Loading

Shimming

预置依赖
ProvidePlugin 自动加载模块,而不必在任何地方导入或要求它们

// 我们还可以使用ProvidePlugin通过为模块导出一个“数组路径”(例如[module,child,... children?])来配置该模块的单个导出
new webpack.ProvidePlugin({
    
    
  _map: ['lodash', 'map'],
});
Usage

Web Workers

webpack5 在没有worker-loader的情况下,可以用Web Workers

Asset Modules

Asset Modules 通过添加4种新的模块类型来替换所有这些加载程序:

  • asset/resource:以前可以通过使file-loader来实现
  • asset/inline:以前可以通过使用url-loader实现
  • asset/source:以前可以通过使用raw-loader来实现
  • asset:以前可以通过使用具有资产大小限制的url-loader来实现

猜你喜欢

转载自blog.csdn.net/u013270347/article/details/115751374