谷歌云做网站/产品推广软件有哪些
webpack概念
概念
Webpack
是一种用于构建 JavaScript
应用程序的静态模块打包器,它能够以一种相对一致且开放的处理方式,加载应用中的所有资源文件(图片、CSS
、视频、字体文件等),并将其合并打包成浏览器兼容的 Web
资源文件。
功能
- 模块的打包:通过打包整合不同的模块文件保证各模块之间的引用和执行
- 代码编译:通过丰富的
loader
可以将不同格式文件如.sass/.vue/.jsx
转译为浏览器可以执行的文件 - 扩展功能:通过社区丰富的
plugin
可以实现多种强大的功能,例如代码分割、代码混淆、代码压缩、按需加载等等
entry
单入口
将源文件加入到 webpack 构建流程,可以是单入口
module.exports = {entry: `./index.js`,
}
构建包名称 [name]
为 main
多入口
也可以是多入口
module.exports = {entry: { "index": `./index.js`,"product":`./product.js`,},
}
key:value
键值对的形式:
- key:构建包名称,即
[name]
,在这里为index
- value:入口路径
入口决定 webapck
从哪个模块开始生成依赖关系图(构建包),每一个入口文件都对应着一个依赖关系图。
动态配置入口文件
动态打包所有子项目
当构建项目包含多个子项目时,每次增加一个子系统都需要将入口文件写入 webpack
配置文件中,其实我们让 webpack
动态获取入口文件
// 使用 glob 等工具使用若干通配符,运行时获得 entry 的条目
module.exports = {entry: glob.sync('./project/**/index.js').reduce((acc, path) => {const entry = path.replace('/index.js', '')acc[entry] = pathreturn acc}, {}),
}
则会将所有匹配 ./project/**/index.js
的文件作为入口文件进行打包,如果你想要增加一个子项目,仅仅需要在 project
创建一个子项目目录,并创建一个 index.js
作为入口文件即可。
这种方式比较适合入口文件不集中且较多的场景。
动态打包某一子项目
在构建多系统应用或组件库时,我们每次打包可能仅仅需要打包某一模块,此时,可以通过命令行的形式请求打印某一模块
npm run build --project components
在打包的时候解析命令行参数:
// 解析命令行参数
const argv = require('minimist')(process.argv.slice(2))
// 项目
const project = argv['project'] || 'index'
然后配置入口:
module.exports = {entry: { "index": `./${project}/index.js`,}
}
相当于:
module.exports = {entry: { "index": `./components/index.js`,}
}
output
用于告知 webpack
如何构建编译后的文件,可以自定义输出文件的位置和名称:
module.exports = {output: { // path 必须为绝对路径// 输出文件路径path: path.resolve(__dirname, '../../dist/build'),// 包名称filename: "[name].bundle.js",// 或使用函数返回名(不常用)// filename: (chunkData) => {// return chunkData.chunk.name === 'main' ? '[name].js': '[name]/[name].js';// },// 块名,公共块名(非入口)chunkFilename: '[name].[chunkhash].bundle.js',// 打包生成的 index.html 文件里面引用资源的前缀// 也为发布到线上资源的 URL 前缀// 使用的是相对路径,默认为 ''publicPath: '/', }
}
文件指纹策略
对于我们开发的每一个应用,浏览器都会对静态资源进行缓存,如果我们更新了静态资源,而没有更新静态资源名称(或路径),浏览器就可能因为缓存的问题获取不到更新的资源。
Webpack
文件指纹策略是将文件名后面加上 hash
值。特别在使用 CDN
的时候,缓存是它的特点与优势,但如果打包的文件名,没有 hash
后缀的话,你肯定会被缓存折磨的够呛
在定义包名称(例如 chunkFilename
、 filename
),我们一般会用到哈希值,不同的哈希值使用的场景不同
hash
build-specific
, 哈希值对应每一次构建( Compilation
),即每次编译都不同,即使文件内容都没有改变,并且所有的资源都共享这一个哈希值,此时,浏览器缓存就没有用了,可以用在开发环境,生产环境不适用。
chunkhash
chunk-specific
, 哈希值对应于 webpack
每个入口点,每个入口都有自己的哈希值。如果在某一入口文件创建的关系依赖图上存在文件内容发生了变化,那么相应入口文件的 chunkhash
才会发生变化,适用于生产环境
contenthash
content-specific
,根据包内容计算出的哈希值,只要包内容不变, contenthash
就不变,适用于生产环境
webpack
也允许哈希的切片。如果你写 [hash:8]
,那么它会获取哈希值的前 8 位。
打包成库
当使用 webapck
构建一个可以被其它模块引用的库时:
module.exports = {output: { // path 必须为绝对路径// 输出文件路径path: path.resolve(__dirname, '../../dist/build'),// 包名称filename: "[name].bundle.js",// 块名,公共块名(非入口)chunkFilename: '[name].[chunkhash].bundle.js',// 打包生成的 index.html 文件里面引用资源的前缀// 也为发布到线上资源的 URL 前缀// 使用的是相对路径,默认为 ''publicPath: '/', // 一旦设置后该 bundle 将被处理为 librarylibrary: 'webpackNumbers',// export 的 library 的规范,有支持 var, this, commonjs,commonjs2,amd,umdlibraryTarget: 'umd',}
}
配置模式 mode
设置 mode
,可以让 webpack
自动调起相应的内置优化
module.exports = {// 可以是 none、development、production// 默认为 productionmode: 'production'
}
或在命令行里配置:
"build:prod": "webpack --config config/webpack.prod.config.js --mode production"
在设置了 mode
之后, webpack
会同步配置 process.env.NODE_ENV
为 development
或 production
。
production
配置:
// webpack.prod.config.js
module.exports = {mode: 'production',
}
相当于默认内置了:
// webpack.prod.config.js
module.exports = {performance: {// 性能设置,文件打包过大时,会报警告hints: 'warning'},output: {// 打包时,在包中不包含所属模块的信息的注释pathinfo: false},optimization: {// 不使用可读的模块标识符进行调试namedModules: false,// 不使用可读的块标识符进行调试namedChunks: false,// 设置 process.env.NODE_ENV 为 productionnodeEnv: 'production',// 标记块是否是其它块的子集// 控制加载块的大小(加载较大块时,不加载其子集)flagIncludedChunks: true,// 标记模块的加载顺序,使初始包更小occurrenceOrder: true,// 启用副作用sideEffects: true,// 确定每个模块的使用导出,// 不会为未使用的导出生成导出// 最小化的消除死代码// optimization.usedExports 收集的信息将被其他优化或代码生成所使用usedExports: true,// 查找模块图中可以安全的连接到其它模块的片段concatenateModules: true,// SplitChunksPlugin 配置项splitChunks: {// 默认 webpack4 只会对按需加载的代码做分割chunks: 'async',// 表示在压缩前的最小模块大小,默认值是30kbminSize: 30000,minRemainingSize: 0,// 旨在与HTTP/2和长期缓存一起使用 // 它增加了请求数量以实现更好的缓存// 它还可以用于减小文件大小,以加快重建速度。maxSize: 0,// 分割一个模块之前必须共享的最小块数minChunks: 1,// 按需加载时的最大并行请求数maxAsyncRequests: 6,// 入口的最大并行请求数maxInitialRequests: 4,// 界定符automaticNameDelimiter: '~',// 块名最大字符数automaticNameMaxLength: 30,cacheGroups: { // 缓存组vendors: {test: /[\\/]node_modules[\\/]/,priority: -10},default: {minChunks: 2,priority: -20,reuseExistingChunk: true}}},// 当打包时,遇到错误编译,将不会把打包文件输出// 确保 webpack 不会输入任何错误的包noEmitOnErrors: true,checkWasmTypes: true,// 使用 optimization.minimizer || TerserPlugin 来最小化包minimize: true,},plugins: [// 使用 terser 来优化 JavaScriptnew TerserPlugin(/* ... */),// 定义环境变量new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),// 预编译所有模块到一个闭包中,提升代码在浏览器中的执行速度new webpack.optimize.ModuleConcatenationPlugin(),// 在编译出现错误时,使用 NoEmitOnErrorsPlugin 来跳过输出阶段。// 这样可以确保输出资源不会包含错误new webpack.NoEmitOnErrorsPlugin()]
}
development
// webpack.dev.config.js
module.exports = {mode: 'development',
}
相当于默认内置了:
// webpack.dev.config.js
module.exports = {devtool: 'eval',cache: true,performance: {// 性能设置,文件打包过大时,不报错和警告,只做提示hints: false},output: {// 打包时,在包中包含所属模块的信息的注释pathinfo: true},optimization: {// 使用可读的模块标识符进行调试namedModules: true,// 使用可读的块标识符进行调试namedChunks: true,// 设置 process.env.NODE_ENV 为 developmentnodeEnv: 'development',// 不标记块是否是其它块的子集flagIncludedChunks: false,// 不标记模块的加载顺序occurrenceOrder: false,// 不启用副作用sideEffects: false,usedExports: false,concatenateModules: false,splitChunks: {hidePathInfo: false,minSize: 10000,maxAsyncRequests: Infinity,maxInitialRequests: Infinity,},// 当打包时,遇到错误编译,仍把打包文件输出noEmitOnErrors: false,checkWasmTypes: false,// 不使用 optimization.minimizer || TerserPlugin 来最小化包minimize: false,removeAvailableModules: false},plugins: [// 当启用 HMR 时,使用该插件会显示模块的相对路径// 建议用于开发环境new webpack.NamedModulesPlugin(),// webpack 内部维护了一个自增的 id,每个 chunk 都有一个 id。// 所以当增加 entry 或者其他类型 chunk 的时候,id 就会变化,// 导致内容没有变化的 chunk 的 id 也发生了变化// NamedChunksPlugin 将内部 chunk id 映射成一个字符串标识符(模块的相对路径)// 这样 chunk id 就稳定了下来new webpack.NamedChunksPlugin(),// 定义环境变量new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),]
}
none
不进行任何默认优化选项。
配置:
// webpack.base.config.js
module.exports = {mode: 'none',
}
相当于默认内置了:
// webpack.base.config.js
module.exports = {performance: {// 性能设置,文件打包过大时,不报错和警告,只做提示hints: false},optimization: {// 不标记块是否是其它块的子集flagIncludedChunks: false,// 不标记模块的加载顺序occurrenceOrder: false,// 不启用副作用sideEffects: false,usedExports: false,concatenateModules: false,splitChunks: {hidePathInfo: false,minSize: 10000,maxAsyncRequests: Infinity,maxInitialRequests: Infinity,},// 当打包时,遇到错误编译,仍把打包文件输出noEmitOnErrors: false,checkWasmTypes: false,// 不使用 optimization.minimizer || TerserPlugin 来最小化包minimize: false,},plugins: []
}
三种模式对比
选项 | 描述 |
---|---|
development | 开发模式,打包更加快速,省了代码优化步骤 |
production | 生产模式,打包比较慢,会开启 tree-shaking 和 压缩代码 |
none | 不使用任何默认优化选项 |
Loader
为什么需要 Loader
webpack
默认支持处理 JS
与 JSON
文件,其他类型都处理不了,这里必须借助 Loader
来对不同类型的文件的进行处理
Loader 的作用
Loader
就是将 Webpack
不认识的内容转化为认识的内容
常用的 Loader
及其作用
babel-loader
:是一个JavaScript
的编译器,可以将新版本的JavaScript
或者采用JavaScript
语法外延扩展,比如将ES6
代码翻译成ES5
代码file-loader
:可以指定要复制和放置资源文件的位置,以及如何使用版本哈希命名以获得更好的缓存,并在代码中通过URL
去引用输出的文件url-loader
: 和file-loader
功能相似,但是可以通过指定阈值来根据文件大小使用不同的处理方式(小于阈值则返回base64
格式编码并将文件的data-url
内联到bundle
中)raw-loader
: 加载文件原始内容image-webpack-loader
: 加载并压缩图片资源awesome-typescirpt-loader
: 将typescript
转换为javaScript
并且性能由于ts-loader
sass-loader
: 将SCSS/SASS
代码转换为CSS
css-loader
: 加载CSS
代码 支持模块化、压缩、文件导入等功能特性style-loader
: 把CSS
代码注入到js
中,通过DOM
操作去加载CSS
代码source-map-loader
: 加载额外的Source Map
文件eslint-loader
: 通过ESlint
检查js
代码cache-loader
: 可以在一些开销较大的Loader
之前添加可以将结果缓存到磁盘中,提高构建的效率thread-loader
: 多线程打包,加快打包速度
Loader 的本质
Loader
本质上是一个函数,负责代码的转译,即对接收到的内容进行转换后将转换后的结果返回 配置 Loader
通过在 modules.rules
中以数组的形式配置
Loader
的执行有以下两个阶段:
Pitching
阶段:loader
上的pitch
方法,按照后置(post)、行内(inline)、普通(normal)、前置(pre)
的顺序调用。Normal
阶段:loader
上的 常规方法,按照前置(pre)、普通(normal)、行内(inline)、后置(post)
的顺序调用。模块源码的转换, 发生在这个阶段。
如何保证众多Loader按照想要的顺序执行
可以通过 enforce
来强制控制 Loader
的执行顺序 。( pre
表示在所有正常的 loader
执行之前执行, post
则表示在之后执行)
Plugin
与 Loader
用于转换特定类型的文件不同,插件( Plugin
)可以贯穿 Webpack
打包的生命周期,执行不同的任务,从而扩展Webpack
的功能
常用的 Plugin 及其作用
define-plugin
: 定义环境变量web-webpack-plugin
: 为单页面应用输出HTML
性能优于html-webpack-plugin
clean-webpack-plugin
: 每次打包时删除上次打包的产物, 保证打包目录下的文件都是最新的。
tips :Webpack 5.20
以后可以通过output.clean
属性达到同样的效果,所以此插件用处不大了terser-webpack-plugin
: 内部封装了terser
库,用于处理js
的压缩和混淆
tips :webpack v5
开箱即带有最新版本的terser-webpack-plugin
。如果你使用的是webpack v5
或更高版本,同时希望自定义配置,那么仍需要安装terser-webpack-plugin
。如果使用webpack v4
,则必须安装terser-webpack-plugin v4
的版本。mini-css-extract-plugin
: 将CSS
提取为独立文件,支持按需加载css-minimize-webpack-plugin
: 压缩CSS
代码
tips:css
文件的压缩需要mini-css-extract-plugin
和css-minimize-webpack-plugin
的配合使用 即先使用mini-css-extract-plugin
将css
代码抽离成单独文件,之后使用css-minimize-webpack-plugin
对css
代码进行压缩compression-webpack-plugin
: 生产环境采用gzip
压缩JS
和CSS
webpack-bundle-analyzer
: 可视化webpack
输出文件大小的根据speed-measure-webpack-plugin
: 用于分析各个loader
和plugin
的耗时,可用于性能分析webpack-dashboard
: 可以更友好地展示打包相关信息
Plugin 的本质
Plugin
本质上是一个带有 apply(compiler)
的函数,基于 tapable
这个事件流框架来监听 webpack
构建/打包过程中发布的 hooks
来通过自定义的逻辑和功能来改变输出结果。 Plugin
通过 plugins
以数组的形式配置
与 Loader 的区别
Loade
r主要负责将代码转译为 webpack
可以处理的 JavaScript
代码,而 Plugin
更多的是负责通过接入 webpack
构建过程来影响构建过程以及产物的输出。
Loader
的职责相对比较单一简单,而 Plugin
更为丰富多样。
devServer
可以通过 webpack-dev-server
启动本地服务
安装 webpack-dev-server
npm intall webpack-dev-server -D
配置 devServer
const path = require('path');module.exports = {//...devServer: {static: {directory: path.join(__dirname, 'public'),},compress: true,port: 9000,},
};
tips : 为什么要配置 static.directory
?
因为 webpack
在进行打包的时候,对静态文件的处理,例如图片,都是直接 copy
到 dist
目录下面。但是对于本地开发来说,这个过程太费时,也没有必要,所以在设置 static.directory
之后,就直接到对应的静态目录下面去读取文件,而不需对文件做任何移动,节省了时间和性能开销。
devServer
详细配置请参考 官网
devtool ( sourceMap
)
SourceMap
是一种映射关系,当项目运行后,如果出现错误,我们可以利用 SourceMap
反向定位到源码位置。在 webpack
中通过 devtool
字段来配置 sourceMap
策略。
配置 devtool
const config = {entry: './src/index.js', // 打包入口地址output: {filename: 'bundle.js', // 输出文件名path: path.join(__dirname, 'dist'), // 输出文件目录},devtool: 'source-map',module: { // ...}// ...
sourcemap 取值比较
devtool | build | rebuild | 显示代码 | SourceMap 文件 |
---|---|---|---|---|
(none) | 很快 | 很快 | 无 | 无 |
eval | 快 | 很快(cache) | 编译后 | 无 |
source-map | 很慢 | 很慢 | 源代码 | 有 |
eval-source-map | 很慢 | 一般(cache) | 编译后 | 有(dataUrl) |
eval-cheap-source-map | 一般 | 快(cache) | 编译后 | 有(dataUrl) |
eval-cheap-module-source-map | 慢 | 快(cache) | 源代码 | 有(dataUrl) |
inline-source-map | 很慢 | 很慢 | 源代码 | 有(dataUrl) |
hidden-source-map | 很慢 | 很慢 | 源代码 | 有 |
nosource-source-map | 很慢 | 很慢 | 源代码 | 无) |
推荐配置
官方推荐
开发环境
以下选项非常适合开发环境:
eval
- 每个模块都使用eval()
执行,并且都有//# sourceURL
。此选项会非常快地构建。主要缺点是,由于会映射到转换后的代码,而不是映射到原始代码(没有从loader
中获取source map
),所以不能正确的显示行数。eval-source-map
- 每个模块使用eval()
执行,并且source map
转换为DataUrl
后添加到eval()
中。初始化source map
时比较慢,但是会在重新构建时提供比较快的速度,并且生成实际的文件。行数能够正确映射,因为会映射到原始代码中。它会生成用于开发环境的最佳品质的source map
。eval-cheap-source-map
- 类似eval-source-map
,每个模块使用eval()
执行。这是"cheap(低开销)"
的source map
,因为它没有生成列映射(column mapping
),只是映射行数。它会忽略源自loader
的source map
,并且仅显示转译后的代码,就像eval devtool
。eval-cheap-module-source-map
- 类似eval-cheap-source-map
,并且,在这种情况下,源自loader
的source map
会得到更好的处理结果。然而,loader source map
会被简化为每行一个映射(mapping
)。
生产环境
这些选项通常用于生产环境中:
(none)
(省略devtool
选项) - 不生成source map
。这是一个不错的选择。source-map
- 整个source map
作为一个单独的文件生成。它为bundle
添加了一个引用注释,以便开发工具知道在哪里可以找到它。hidden-source-map
- 与source-map
相同,但不会为bundle
添加引用注释。如果你只想source map
映射那些源自错误报告的错误堆栈跟踪信息,但不想为浏览器开发工具暴露你的source map
,这个选项会很有用。nosources-source-map
- 创建的source map
不包含sourcesContent
(源代码内容)。它可以用来映射客户端上的堆栈跟踪,而无须暴露所有的源代码。你可以将source map
文件部署到web
服务器。
个人推荐
本地开发
推荐:eval-cheap-module-source-map
理由:
- 本地开发首次打包慢点没关系,因为
eval
缓存的原因,rebuild
会很快 - 开发中,我们每行代码不会写的太长,只需要定位到行就行,所以加上
cheap
- 我们希望能够找到源代码的错误,而不是打包后的,所以需要加上
module
生产环境
推荐:(none)
理由: 不生成 source map
。这是一个不错的选择
resolve
配置模块如何解析。webpack 提供合理的默认值,但是还是可能会修改一些解析的细节。
module.exports = {resolve: {modules: [path.resolve(__dirname,'src'), 'node_modules'],extensions: ['.js', '.jsx', '.react.js', '.css', '.json'],// import导入时别名,减少耗时的递归解析操作alias: {'@components': path.resolve(`${project}/components`),'@style': path.resolve('asset/style'),},},
}
modules
- 设置模块导入规则,
import/require
时会直接在这些目录找文件 - 可以指明存放第三方模块的绝对路径,以减少寻找
- 默认值为
node_modules
- 告诉
webpack
优先src
目录下查找需要解析的文件,会大大节省查找时间
extensions
- 配置
extensions
后,import
导入时可省略后缀 - 注意:尽可能的减少后缀尝试的可能性,故高频文件后缀名放前面
- 手动配置后,默认配置会被覆盖
- 如果想保留默认配置,可以用 … 扩展运算符代表默认配置
如:
const config = {//...resolve: {extensions: ['.ts', '...'], },
};
alias
alias
用的创建 import
或 require
的别名,用来简化模块引用,项目中基本都需要进行配置
optimization
从 webpack 4
开始,会根据你选择的 mode
来执行不同的优化, 不过所有的优化还是可以手动配置和重写。
主要涉及两方面的优化:
- 最小化包
- 拆包
最小化包
removeAvailableModules
如果模块已经包含在所有父级模块中,告知 webpack
从 chunk
中检测出这些模块,或移除这些模块。将 optimization.removeAvailableModules
设置为 true
以启用这项优化。在 production
模式 中默认会被开启。
module.exports = {//...optimization: {removeAvailableModules: true,},
};
removeEmptyChunks
如果 chunk
为空,告知 webpack
检测或移除这些 chunk
,(简单来说就是删除空模块)。默认值为true
,将 optimization.removeEmptyChunks
设置为 false
可以禁用这项优化。
module.exports = {//...optimization: {removeEmptyChunks: false,},
};
providedExports
告知 webpack
去确定那些由模块提供的导出内容,为 export * from ...
生成更多高效的代码。默认 optimization.providedExports
会被启用。
module.exports = {//...optimization: {providedExports: true,},
};
usedExports
告知 webpack
去决定每个模块使用的导出内容。这取决于 optimization.providedExports
选项。由 optimization.usedExports
收集的信息会被其它优化手段或者代码生成使用,比如未使用的导出内容不会被生成,当所有的使用都适配,导出名称会被处理做单个标记字符。 在压缩工具中的无用代码清除会受益于该选项,而且能够去除未使用的导出内容。 默认值为 true
sideEffects
告知 webpack
去辨识 package.json
中的 副作用 标记或规则,以跳过那些当导出不被使用且被标记不包含副作用的模块。
optimization.sideEffects
取决于 optimization.providedExports
被设置成启用。这个依赖会有构建时间的损耗,但去掉模块会对性能有正面的影响,因为更少的代码被生成。该优化的效果取决于你的代码库, 可以尝试这个特性以获取一些可能的性能优化。
splitChunks
提取公共包 。
webpack
将根据以下条件自动拆分 chunks
:
- 新的
chunk
可以被共享,或者模块来自于node_modules
文件夹 - 新的
chunk
体积大于20kb
(在进行min+gz
之前的体积) - 当按需加载
chunks
时,并行请求的最大数量小于或等于 30 - 当加载初始化页面时,并发请求的最大数量小于或等于 30
当尝试满足最后两个条件时,最好使用较大的 chunks
。
下面这个配置对象代表 SplitChunksPlugin
的默认行为。
module.exports = {//...optimization: {splitChunks: {chunks: 'async',minSize: 20000,minRemainingSize: 0,minChunks: 1,maxAsyncRequests: 30,maxInitialRequests: 30,enforceSizeThreshold: 50000,cacheGroups: {defaultVendors: {test: /[\\/]node_modules[\\/]/,priority: -10,reuseExistingChunk: true,},default: {minChunks: 2,priority: -20,reuseExistingChunk: true,},},},},
};
关于 splitChunks
的详细配置请参考 官网
minimizer
允许你通过提供一个或多个定制过的 TerserPlugin
实例,覆盖默认压缩工具(minimizer
)
配合 TerserPlugin
实现代码压缩和变量混淆,以及生产环境去除 console
和 debugger
等
const TerserPlugin = require('terser-webpack-plugin');module.exports = {optimization: {minimizer: [new TerserPlugin({parallel: true,terserOptions: {// https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions},}),],},
};
在 optimization.minimizer
中可以使用'...'
来访问默认值。
module.exports = {optimization: {minimizer: [new CssMinimizer(), '...'],},
};
拆包
当包过大时,如果我们更新一小部分的包内容,那么整个包都需要重新加载,如果我们把这个包拆分,那么我们仅仅需要重新加载发生内容变更的包,而不是所有包,有效的利用了缓存。
拆分 node_modules
很多情况下,我们不需要手动拆分包,可以使用 optimization.splitChunks
:
const path = require('path');
module.exports = {entry: path.resolve(__dirname, 'src/index.js'),output: {path: path.resolve(__dirname, 'dist'),filename: '[name].[contenthash].js',},optimization: {splitChunks: {// 对所有的包进行拆分chunks: 'all',},},
};
我们不必制定拆包策略, chunks: all
会自动将 node_modules
中的所有内容放入一个名为 vendors〜main.js
的文件中。
拆分业务代码
module.exports = {entry: {main: path.resolve(__dirname, 'src/index.js'),ProductList: path.resolve(__dirname, 'src/ProductList/ProductList.js'),ProductPage: path.resolve(__dirname, 'src/ProductPage/ProductPage.js'),Icon: path.resolve(__dirname, 'src/Icon/Icon.js'),},output: {path: path.resolve(__dirname, 'dist'),filename: '[name].[contenthash:8].js',},
};
采用多入口的方式,当有业务代码更新时,更新相应的包即可
拆分第三方库
const path = require('path');
const webpack = require('webpack');module.exports = {entry: path.resolve(__dirname, 'src/index.js'),output: {path: path.resolve(__dirname, 'dist'),filename: '[name].[contenthash].js',},optimization: {runtimeChunk: 'single',splitChunks: {chunks: 'all',maxInitialRequests: Infinity,minSize: 0,cacheGroups: {vendor: {test: /[\\/]node_modules[\\/]/,name(module) {// 获取第三方包名const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];// npm 软件包名称是 URL 安全的,但是某些服务器不喜欢@符号return `npm.${packageName.replace('@', '')}`;},},},},},
};
当第三方包更新时,仅更新相应的包即可。
注意,当包太多时,浏览器会发起更多的请求,并且当文件过小时,对代码压缩也有影响。
performance
当打包时出现超过特定文件限制的资产和入口点, performance
配置如何显示性能提示
module.exports = {performance: {// 可选 warning、error、false// false:性能设置,文件打包过大时,不报错和警告,只做提示// warning:显示警告,建议用在开发环境// error:显示错误,建议用在生产环境,防止部署太大的生产包,从而影响网页性能hints: false}
}
watch
监视文件更新,并在文件更新时重新编译:
module.export = {// 启用监听模式watch: true,
}
在 webpack-dev-server
和 webpack-dev-middleware
中,默认启用了监视模式。
或者我们可以在命令行里启动监听( --watch
):
webpack --watch --config webpack.dev.config.js
watchOptions
module.export = {watch: true,// 自定义监视模式watchOptions: {// 排除监听ignored: /node_modules/,// 监听到变化发生后,延迟 300ms(默认) 再去执行动作,// 防止文件更新太快导致重新编译频率太高aggregateTimeout: 300,// 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的// 默认 1000ms 询问一次poll: 1000}
}
externals
排除打包时的依赖项,不纳入打包范围内,例如你项目中使用了 jquery
,并且你在 html
中引入了它,那么在打包时就不需要再把它打包进去:
<scriptsrc="https://code.jquery.com/jquery-3.1.0.js"integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="crossorigin="anonymous">
</script>
配置:
module.exports = {// 打包时排除 jquery 模块externals: {jquery: 'jQuery'}
};
target
构建目标,用于为 webpack
指定一个环境:
module.exports = {// 编译为类浏览器环境里可用(默认)target: 'web'
};
cache
缓存生成的 webpack
模块和块以提高构建速度。在开发模式中,缓存设置为 type: 'memory'
,在生产模式中禁用。 cache: true
是 cache: {type: 'memory'}
的别名。要禁用缓存传递 false
:
module.exports = {cache: true
}
在内存中,缓存仅在监视模式下有用,并且我们假设你在开发中使用监视模式。 在不进行缓存的情况下,内存占用空间较小。
name
module.exports = {name: 'react-app'
};
相关文章:

万字长文详解webpack知识图谱
webpack概念 概念 Webpack 是一种用于构建 JavaScript 应用程序的静态模块打包器,它能够以一种相对一致且开放的处理方式,加载应用中的所有资源文件(图片、CSS、视频、字体文件等),并将其合并打包成浏览器兼容的 Web…...

模板测试(Stencil Test)
模板测试可以用来针对特殊的区域进行渲染控制,实现有趣的效果,例如绘制物体轮廓。在 使用模板测试的时候,一般的步骤如下: 启用模板测试,以便写入数值到模板缓冲中渲染物体,根据渲染的物体将特定的数值写入到模板缓冲中禁用模板缓冲写入设置模板函数,根据于模板缓冲中的…...

【Go语言学习】安装与配置
文章目录前言一、Go语言学习站二、安装与配置1.安装2.环境变量配置3.Gland编辑器安装与配置Hello, World!总结前言 Go语言特性 Go,又称为 Golang,是一门开源的编程语言,由 Google 开发。Go 语言的设计目标是提供一种简单、快速、高效、安全…...

HCIP-5OSPF区域类型学习笔记
1、OSPF区域类型 OSPF提出了区域的概念(AREA),区域是将所有运行OSPF 的路由器人为的分成不同的组,以区域ID来标示。在区域内路由计算的方法不变,由于划分区域之后,每个区域内的路由器不会很多,…...

C语言再学习第三章
例题3-1 编写一个函数,实现华氏度和摄氏度的转化。 已知公式:c (5/9)*(f-32) #include <stdio.h>double f_value 0; double c_value 0; int main(void) {printf("请输入华氏温度\n");scanf("%lf",&f_valu…...

【aiy篇】小目标检测综述
小目标检测(Small Object Detection)是指在图像中检测尺寸较小的目标物体,通常是指物体的尺寸小于图像大小的1/10或者更小,COCO为例,面积小于等于1024像素的对象维下目标。小目标检测是计算机视觉领域的一个重要研究方…...

常用Linux命令的基本使用
序号 命令 对应英文 作用 1 ls list 查看当前文件夹下的内容 2 pwd print work directory 查看当前所在文件夹 3 cd[目录名] changge directory 切换文件夹 4 touch[文件名] touch 如果文件不存在,新建文件 5 mkdir[目录名] make directory …...

对跳表的深入理解
一,如何理解跳表 简单说跳表(Skip list)就是链表的“二分查找”。redis 的有序集合用的就是跳表算法。跳表是一种各方面性能都比较优秀的动态数据结构,可以支持快速地插入、删除、查找操作,写起来也不复杂,…...

C++017-C++冒泡排序与插入排序
文章目录C017-C冒泡排序与插入排序冒泡排序与插入排序目标冒泡排序排序规则冒泡排序优化插入排序题目描述在线练习:总结C017-C冒泡排序与插入排序 在线练习: http://noi.openjudge.cn/ https://www.luogu.com.cn/ 冒泡排序与插入排序 参考:…...

数据结构基础之链表
目录 前言 1、什么是链表 2、添加元素 3、虚拟头结点 4、查询&修改元素 5、删除元素 附:完整代码 前言 又到周末了,修整了一天,继续来写点东西吧,今天,我们来学习数据结构中的另一种基础的数据结构——链表…...

css 的渲染层合成是什么,浏览器如何创建新的渲染层
在 DOM 树中每个节点都会对应一个渲染对象(RenderObject),当它们的渲染对象处于相同的坐标空间(z 轴空间)时,就会形成一个 RenderLayers,也就是渲染层。渲染层将保证页面元素以正确的顺序堆叠&a…...

nacos-sdk-rust binding to NodeJs
广告时间 nacos-sdk-rust-binding-node : nacos-sdk-rust binding to NodeJs with napi. Tip: nacos-sdk-nodejs 仓库暂未提供 2.x gRPC 交互模式,为了能升级它,故而通过 node addon 方式调用 nacos-sdk-rust npm 包 -> https://www.npmjs.com/packa…...

MySQL下载安装以及环境配置教程
目录MySQL 下载MySQL 安装配置环境变量MySQL 下载 进入官方网站 https://www.mysql.com/ 点击 DOWNLOADS 进入下载页面 免费版本点击下方的 MySQL Community (GPL) Downloads 点击 MySQL Community Server 点击 Go to Download Page 进入下载页面 点击 Download 点击 No thank…...

概率论 1.3 古典概型与几何概型
1.3.1 排列与组合排列从n个不同元素任取r(r<n)个元素排成一列(考虑元素出现的先后次序),称此为一个排列,此种排列的总数为n(n-1)....(n-r1)n!/(n-r)!,若rn,则称为全排列,2.重复排列从n个不同元素中每次取出一个,放回…...

HTML DOM
通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素。HTML DOM (文档对象模型)当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。HTML DOM 定义了用于 HTML 的一系列标准的对象,以及访问和处…...

Vue组件-$refs、$nextTick和name属性的使用
Vue组件-$refs和$nextTick使用一、获取DOM二、$refs获取组件对象三、$nextTick异步更新DOM四、组件name属性的使用一、获取DOM 通过id或ref属性获取原生DOM 在mounted生命周期 – 2种方式获取原生DOM标签 目标标签 – 添加id / ref恰当时机, 通过id / 通过ref属性 获取目标标签…...

【Spark】Spark的DataFrame向Impala写入数据异常及源码解析
背景 事情是这样的,当前业务有一个场景: 从业务库的Mysql抽取数据到Hive 由于运行环境的网络限制,当前选择的方案: 使用spark抽取业务库的数据表,然后利用impala jdbc数据灌输到hive。(没有spark on hive 的条件&…...

学习笔记-架构的演进之限流-3月day03
文章目录前言限流的目标流量统计指标限流设计模式流量计数器模式滑动时间窗模式漏桶模式令牌桶模式分布式限流总结附前言 任何一个系统的运算、存储、网络资源都不是无限的,当系统资源不足以支撑外部超过预期的突发流量时,就应该要有取舍,建…...

动态规划 背包问题
动态规划 背包问题 问题描述: 有一个背包,总容量为12。有6件物品,每件物品的重量和价值不同,求在背包总容量12的前提下,装进物品的最大价值以及装进物品的编号 单个物品重量和价值: 为方便进行思考&#…...

C++ Primer Plus 学习笔记(四)—— 内存模型和名称空间
1 单独编译 C允许将组件函数放在独立的文件即头文件中,头文件中可以包含以下内容: 函数原型;使用#define或const定义的符号常量;结构声明;类声明;模板声明;内联函数。 注意,在包含…...

详解基于 Celestia、Eclipse 构建的首个Layer3 链 Nautilus Chain
以流支付为主要概念的Zebec生态,正在推动流支付这种新兴的支付方式向更远的方向发展,该生态最初以Zebec Protocol的形态发展,并从初期的Solana进一步拓展至BNB Chian以及Near上。与此同时,Zebec生态也在积极的寻求从协议形态向公链…...

列表与数组的转化
目录用np.array(a)将列表转换为数组列表转数组的特殊情况(一)列表转数组的特殊情况(二)针对子元素个数不一致的解决办法用a.tolist()函数将数组转化为列表在python的学习中,经常会用到数组与列表的相互转化,本文主要介绍下关于数组与列表转化的问题。用n…...

docker 运行花生壳实现内外网穿透
环境:centos 7 ,64位 1、创建一个指定的文件夹作为安装示例所用,该示例文件夹为“hsk-nwct”。“hsk-nwct”内创建“app”文件夹作为docker容器挂载出来的文件。 2、在“app”内下载花生壳linux安装包,下载花生壳应用:花生壳客户…...

操作系统——16.时间片轮转、优先级、多级反馈队列算法
这篇文章我们来看一下进程调度算法中的时间片轮转、优先级、多级反馈队列算法 目录 1.概述 2.时间片轮转调度算法(RR,Round-Robin) 3.优先级调度算法 4.多级反馈队列调度算法 5.分析对比 1.概述 首先,我们来看一下这篇文章…...

Python3.8.8-Django3.2-Redis-连接池-数据类型-字符串-list-hashmap-命令行操作
文章目录1.认识Redis1.1.优点1.2.缺点2.在Django中Redis的连接3.Redis的基础用法3.1.hashmap结构3.2.list结构4.命令行查看数据库5.作者答疑1.认识Redis Remote DIctionary Server(Redis) 是一个key-value 存储系统,是跨平台的非关系型数据库。是一个开源的使用 AN…...

Android kotlin 系列讲解(进阶篇)高级项目架构模式 - MVVM
<<返回总目录 1、MVVM是什么 MVVM是Model-View-ViewModel的缩写,是一种高级项目架构模式。 MVVM架构可以将程序结构主要分成三个部分: Model:数据模型部分,包括从服务端获取的json数据或者从本地获取的数据等等View&…...

8. 查找
1 题目描述 查找成绩10开启时间2021年09月24日 星期五 18:00折扣0.8折扣时间2021年11月15日 星期一 00:00允许迟交否关闭时间2021年11月23日 星期二 00:00 输入 n(n ≤ 10^6)个不超过 10^9的单调不减的(就是后面的数字不小于前面的数字)非负整数 &#…...

二分查找算法
感谢“五点七边”工作室的算法讲解,详细内容可以参考视频讲解 二分查找为什么总是写错?_哔哩哔哩_bilibili 此处仅是个人学习总结 以target等于5为例,输入: 1 2 3 5 5 5 8 9 1. 找到第一个 > target 的元素 判断条件 < target&am…...

Git(3)之远程服务器
Git基础之远程服务器 Author:onceday date:2023年3月5日 满满长路有人对你微笑过嘛… windows安装可参考文章:git简易配置_onceday_CSDN博客 參考文档: 《progit2.pdf》,Progit2 Github。《git-book.pdf》 文章目…...

Javalin解构
Javalin Javalin是一个轻量级http框架,我们可以很容易的了解请求的处理过程及其设计,具有较高的学习意义。 从demo说起 public static void main(String[] args) {Javalin app Javalin.create(config -> {System.out.println("用户配置"…...