农庄网站模板,网站 文件夹 上传,深圳网站建设公司佳速互联,杭州商城app开发一文了解webpack入门进阶知识#x1f93e;♀️序言#x1f3d3;一、Tree Shaking1. 引例阐述2. Tree Shaking配置#x1f3f8;二、Development和Prodiction模式的区分打包1. 项目打包结构2. 共有配置webpack.common.js3. 开发环境webpack.dev.js4. 生产环境webpack.prod.j… 一文了解webpack入门进阶知识♀️序言一、Tree Shaking1. 引例阐述2. Tree Shaking配置二、Development和Prodiction模式的区分打包1. 项目打包结构2. 共有配置webpack.common.js3. 开发环境webpack.dev.js4. 生产环境webpack.prod.js5. 运行项目package.json⚽三、Webpack和Code Splitting、SplitChunksPlugin1. 代码分割-Code Splitting2. 引例阐述-SplitChunksPlugin3. 实现方式-SplitChunksPlugin4. SplitChunksPlugin配置参数四、打包分析PreloadingPrefetching1. 打包分析2. Preloading、Prefetching1引例阐述2preloading和prefetching五、CSS文件的代码分割1. css文件代码分割2. 压缩css文件3. 合并打包css文件六、webpack与浏览器缓存1. 浏览器缓存配置2. 解决旧版本问题⚾七、Shimming的作用1. Shimming垫片2. this指向️八、结束语彩蛋 One More Thing(往期推荐(番外篇♀️序言
上一篇文章中我们讲到了 webpack 的一些基础特性但是呢单单会基础特性还是远远不够的。因此在今天的文章中将给大家带来 webpack 的高级特性包括但不限于 dev 环境和 prod 环境的区分打包以及使用 webpack 对项目进行代码分割等等技巧。
废话不多说下面开始进入今天的学习吧~
一、Tree Shaking
1. 引例阐述
假设现在我们有一个需求写一段程序来对两个数做加法和减法。现在我们来实现这个功能。具体代码如下
export const add (a, b) {console.log(a b);
}export const minus (a, b) {console.log(a - b);
}
接下来我们在入口文件引入它。具体代码如下
import { add } from ./math.js;add(1, 2);在这种状态下我们用 npx webpack 命令来对项目进行打包。查看打包后的文件代码
/***/ ./src/math.js:
/*!*********************!*\!*** ./src/math.js ***!\*********************/
/*! exports provided: add, minus */
/***/ (function(module, __webpack_exports__, __webpack_require__) {use strict;
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, add, function() { return add; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, minus, function() { return minus; });
const add (a, b) {console.log(a b);
};
const minus (a, b) {console.log(a - b);
};/***/ })我们可以发现在入口文件我们只引入了加法的操作因为我们当下只想用到加法功能而暂时还不需要用减法。但是呢打包后的文件把减法部分的内容也一起给打包进去了。这无形之中多多少少给我们添加了不少麻烦。
因此呢我们就需要引入 webpack 中的 Tree Shaking 来解决这个问题。
2. Tree Shaking配置
首先我们需要在 webpack.common.js 里面进行配置。如果是在 Development 的模式下那么默认是不拥有 Tree Shaking 的。因此需要进行以下配置具体代码如下
//node的核心模块
const path require(path);
const HtmlWebpackPlugin require(html-webpack-plugin);
const CleanWebpackPlugin require(clean-webpack-plugin);
const webpack require(webpack);module.exports {mode:development,optimization: {usedExports: true}
}在开发环境下我们需要加上 optimization 模块来对项目开启 Tree Shaking 。 接下来我们继续对 package.json 进行配置。在这个文件下我们需要添加以下代码
{sideEffects: false
}sideEffects:false 指的是什么意思呢当设置为 false 时表明对所有的 ES Module 开启 Tree Shaking 操作。
值得注意的是 Tree Shakig 只支持 ES Module 这种类型的引入并不支持 commonJS 等类型的引入。这是因为 ES Module 的底层实现是静态的而 commonJS 的实现则是动态的。 还有另外一种情况就是如果你想要使得某些模块不开启 Tree Shaking 那么可以将 sideEffects 进行以下配置。具体代码如下
{sideEffects: [*.cssbabel/poly-fill ]
}以上代码的意思为对所有的 css 文件以及 babel/poly-fill 不开启 Tree-shaking 功能。 接下来我们来看一下配置完成之后在开发环境下的效果。具体代码如下
/***/ ./src/math.js:
/*!*********************!*\!*** ./src/math.js ***!\*********************/
/*! exports provided: add, minus */
/*! exports used: add */
/***/ (function(module, __webpack_exports__, __webpack_require__) {use strict;
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, a, function() { return add; });
/* unused harmony export minus */
const add (a, b) {console.log(a b);
};
const minus (a, b) {console.log(a - b);
};/***/ })/******/ });
//# sourceMappingURLmain.js.map大家可以看到如果是在开发模式下减法功能依然是存在的只是多个一句 /*! exports used: add */ 来表明只使用 add 这个功能。
这是为什么呢因为在开发模式下 webpack 怕这个地方如果引入了其他模块那么删除就很容易导致报错所以它没有进行删除。 但如果 mode 是在生产环境下时 Tree Shaking 的作用就比较明显了。我们修改完 mode 后来看下打包后的结果。具体代码如下
function (e, n, r) { use strict; r.r(n); var t, o; t 1, o 2, console.log(t o) }生产环境下打包后只有一行小编摘取了最终要的部分出来。
大家可以看到当处于生产环境下时打包后的结果只显示了加法功能。而我们没有使用到减法所以这个时候就不会连带着打包出来了。
顺带着这个话题接下来我们就来讲一下 webpack 在 development 和 Production 模式下的区分打包。
二、Development和Prodiction模式的区分打包
1. 项目打包结构
通常情况下我们的项目会有三个 webpack 的配置文件。一个是 webpack.common.js 一个是 webpack.dev.js 另外一个是webpack.prod.js 。第一个文件用来放开发环境和生产环境下共同的配置第二个文件用来放开发环境下的配置第三个文件用来放生产环境下的配置。
接下来我们来了解下这三个配置文件的代码。
2. 共有配置webpack.common.js
如果我们不编写 common 文件的话那么 dev 和 prod 这两个文件的代码重合度就会比较高所以我们把相同的部分抽离出来。具体代码如下
//node核心模块
const path require(path);
const HtmlWebpackPlugin require(html-webpack-plugin);
const CleanWebpackPlugin require(clean-webpack-plugin);module.exports {// 放置入口文件明确怎么打包entry:{main: ./src/index.js},module:{rules:[{test: /\.m?js$/,//exclude顾名思义即排除在外。如果js文件在node_modules文件夹下面那么我们就排除在外// 因为node_module一般都是来自于第三方库它已经自动的处理好此部分工作所以我们没必要再去做重复操作exclude: /node_modules/,use: {loader: babel-loader,}},{test:/\.(jpg|png|gif)$/,use:{loader:file-loader,options: {//placeholder 占位符name: [name]_[hash].[ext],outputPath: images/,limit: 10240}}},{test:/\.scss$/,use:[style-loader, {loader: css-loader,options: {//表明前面要先走sass-loader和postcss-loaderimportLoaders: 2,modules: true}}, sass-loader,postcss-loader]},{test:/\.css$/,use:[style-loader,css-loader,postcss-loader]},{test: /\.(eot|ttf|svg)$/,use: {loader: file-loader,}}]},plugins: [new HtmlWebpackPlugin({//表明要引用哪一个模板template: src/index.html}),new CleanWebpackPlugin([dist])],// 输出表明webpack应该怎么输出output: {publicPath: /,//用[]可以生成多个文件filename: [name].js,// 指打包后的文件要放在哪个文件下path: path.resolve(__dirname, dist)}
}3. 开发环境webpack.dev.js
抽离完 common 代码之后现在我们来编写 webpack.dev.js 文件。具体代码如下
const webpack require(webpack);
const merge require(webpack-merge);
const commonConfig require(./webpack.common.js);const devConfig {mode:production,devtool: cheap-module-eval-source-map,devServer: {contentBase: ./dist,// 当运行完npm run start时会自动的帮我们打开浏览器open: true,port: 8080,// 让我们的webpackDevServer开启hotModuleReplacement这样子的功能hot: true,// 即便HMR没有生效也不让浏览器自动刷新hotOnly: true},plugins: [//热模块更新new webpack.HotModuleReplacementPlugin()],optimization: {usedExports: true}
}module.exports merge(commonConfig, devConfig)4. 生产环境webpack.prod.js
继续我们来编写抽离后的 prod 代码。具体代码如下
const merge require(webpack-merge);
const commonConfig require(./webpack.common.js);const prodConfig {mode:development,devtool: cheap-module-source-map
}module.exports merge(commonConfig, prodConfig)到这里大家对比上面三个文件的代码可以发现这样的代码抽离使得我们的项目结构变得更为清晰了。
5. 运行项目package.json
上面配置完成之后我们现在要来想一下想要运行开发环境和生产环境不用的配置是不是应该把运行命令也给区分开来。因此我们对 package.json 文件做出以下配置
{scripts: {dev: webpack-dev-server --config webpack.dev.js,build: webpack --config webpack.prod.js}
}通过以上配置那么我们就可以通过命令 npm run dev 和 npm run build 来运行项目以此来区分项目是开发环境还是生产环境。 同时如果我们想要在控制台更直观的看到报错信息那么在开发环境的情况下我们可以不用 webpack-dev-server 来运行可以直接用用 webpack 来运行。具体代码如下
{scripts: {dev-server: webpack --config webpac.dev.js,dev: webpack-dev-server --config webpack.dev.js,build: webpack --config webpack.prod.js}
}这样我们就可以通过 npm run dev-build 来使用 webpack 来运行项目。
⚽三、Webpack和Code Splitting、SplitChunksPlugin
1. 代码分割-Code Splitting
有时候我们可能会遇到一个业务逻辑里面有上万行代码那么这上万行代码打包后全部就丢到 main.js 文件里面了这样大的文件会使得整个项目的加载速度会变得很是缓慢。因此我们就需要用到代码分割Code Splitting来解决这件事情。
我们在 webpack.common.js 中进行配置。具体代码如下
module.exports {optimization: {splitChunks: {chunks: all}}
}通过以上代码我们可以得知通过使用 optimization 中的 splitChunks 达到了代码分割的效果。
那使用这个配置之后 webpack 想要做的事情是什么呢
事实上使用 splitChunks 之后那么当 webpack 遇到公用的类库时会帮我们自动地打包生成一个新的文件之后再把其余的业务逻辑拆分到另外一个文件中去。
值得注意的是公用类库不管是以同步的方式还是以异步的方式进行加载 webpack 都能够帮我们进行代码分割。
2. 引例阐述-SplitChunksPlugin
上面我们讲到了 webpack 的代码分割那么实际上 webpack 的代码分割其底层实现原理所使用的是 splitChunksPlugin 这个插件。接下来我们来讲一下这个插件。
在没有用 SplitChunksPlugin 这个插件之前如果我们异步引入一个库那么 webpack 给其打包后的文件名将会命名为 0.js 、 1.js 和 ...... 。
我们现在希望在做代码分割时 webpack 能给我们的第三方库进行自定义命名这又该怎么处理呢
3. 实现方式-SplitChunksPlugin
首先我们对引入的库前面添加 webpackChunkName 配置。具体代码如下
function getComponent() {return import(/*webpackChunkName:lodash*/lodash).then(({ default: _ }) {var element document.createElement(div);element.innerHTML _.join([Monday, Tuesday], _);return element;})
}getComponent().then(element {document.body.appendChild(element);
})/*webpackChunkName:lodash*/ 这句话想要表明的意思为当我们异步的引入 lodash 这个库并且想要做代码分割时即当我们给 webpack 进行打包时给其起名为 lodash 。 上面这个配置知识第一步接下来我们要来安装并使用一个动态引入的插件。具体代码如下
安装插件
npm install --save-dev babel/plugin-syntax-dynamic-import在 .babelrc 下引入
{// plugins: [dynamic-import-webpack] 非官方支持插件plugins: [babel/plugin-syntax-dynamic-import]
}配置 webpack.common.js
module.exports {optimization: {splitChunks: {chunks: all,cacheGroups: {vendors: false,default: false}}},
}4. SplitChunksPlugin配置参数
接下来我们再来看关于 SplitChunksPlugin 的一些常用配置。具体代码如下
module.exports {optimization: {splitChunks: {/*使用async时只对异步代码进行代码分割使用all时对同步和异步代码同时进行代码分割;使用initial时表示对同步代码进行代码分割*/chunks: all,//大于30kb时做代码分割minSize: 30000,//表明代码分割后文件最大的大小如果超过了则会继续进行拆分有一些文件如果拆分不了则此配置想基本就没啥用了maxSize: 0,minRemainingSize: 0,//至少有两个块被使用了才会被提取minChunks: 2,//表示同时加载的模块数最多是5个/*比如我们引入了10个类库那么我们会做10次代码分割。而这个时候我们将此参数填为5那么webpack在打包时会将前10个库给我们生成5个js文件之后的就不会再做代码分割了全部丢到一个文件里面去*/maxAsyncRequests: 5,//入口文件做代码分割最多只能分割成3个js文件超过3个就不会再做代码分割了maxInitialRequests: 3,//文件生成时的中间符号automaticNameDelimiter: ~,//让defaultVendors和default中的文件名有效name: true,enforceSizeThreshold: 50000,//当打包同步代码时cacheGroupscacheGroups: {defaultVendors: {//检测你引入的库查询是否是在node_module下的test: /[\\/]node_modules[\\/]/,priority: -10,//确定是在node_modules下后将其进行打包并命名为vendors.jsfilename: vendors.js},//对非第三方库的代码做代码分割default: {priority: -20,reuseExistingChunk: true,filename: common.js}},}}
}四、打包分析PreloadingPrefetching
1. 打包分析
打包分析指的是当我们使用 webpack 来进行代码打包之后我们可以借助打包分析的一些工具来对我们打包生成的文件进行一定的分析之后来看其打包的是否合理。那么如何进行打包分析呢
我们要用到一个 github 的第三方仓库戳此链接进入~
了解完文档该库的内容后接下来我们要对 package.json 进行配置。具体代码如下
{scripts: {dev-build: webpack --profile --json stats.json --config ./build/webpack.dev.js,dev: webpack-dev-server --config ./build/webpack.dev.js,build: webpack --config ./build/webpack.prod.js}
}通过上面的代码我们可以分析在 --config 前面加上配置 --profile --json stats.json 意思为 webpack 打包后会生成打包分析文件这个文件叫做 stats.json 同时 --json 表示的意思为 stats.json 文件的格式是一个 json 格式的。 在生成完 stats.json 文件以后我们就可以把它放到打包工具里进行分析。大家可以定位到官方文档中的 bundle-analysis 里面提供了 webpack-chart 、 webpack-visualizer 等可视化工具供我们使用这个可以依据个人需求选择对应的工具对 stats.json 文件进行分析。
2. Preloading、Prefetching
1引例阐述
事实上当我们配置 splitChunks 时里面的 chunks 默认值是 async 。也就是说如果我们不对它进行配置那 webpack 默认只对异步代码进行代码分割。 webpack 为什么要这么做呢
webpack认为把同步代码打包在一个文件就好了同时呢它希望我们要多写点异步加载代码这样才能让我们的网站性能得到真正的提升。
现在我们来说一个生活中一个非常常见的场景。假设现在我们在登录知乎网站那么刚进去的时候我们是还没有登录的。我们现在希望的是点击登录这个按钮登录对应的模态框就能显示出来而不是点击完还要等到它加载这无形这种就可以使得页面加载速度变快了许多。
那这该怎么处理呢这就要谈到 webpack 中的 preloading 和 prefetching 了。
2preloading和prefetching
假设我们现在要引入一个 click.js 文件那么我们可以这么处理。具体代码如下
document.addEventListener(click, () {// 这句话的意思为当主要的js文件都加载完成之后之后就是网络带宽有空闲的时候它就会偷偷的把 ./click.js 文件给加载好import(/* webpackPrefetch: true */ ./click.js).then(({default: func}) {func();})
});通过以上代码我们可以知道在所引入的文件前面即 ./click.js前面加入 /* webpackPrefetch: true */ 即可达到我们想要的效果。这句话的意思为当主要的 js 文件都加载完成之后这时就是网络带宽有空闲的时候那么 webpack 机会偷偷的在这个时间段把 ./click.js 文件给加载好。
这里说到的是 prefetch 但其实我们也可以把 webpackPrefetch 改成 webpackPreload preload 与 prefetch 的区别在于 preload 是跟主文件同时进行加载而不是在主文件加载完才加载的。一般来说我们都用 prefetch 只有等主文件把活干完了再来加载剩余的我们想要的文件这样的逻辑和对页面的优化才是比较完美的。
综上原先我们打包像 jQuery 、 lodash 之类的库时只需要在第一次访问的时候加载而等到第二次访问的时候我们就可以借助缓存提高访问的速度。但这种方式也只是提高第二次访问的速度而我们想要实现的是当第一次访问的时候 webpack 就可以使得页面的加载速度是最快的。
所以最终我们使用了 preload 和 prefetch 这两种实现方式来解决这个问题。
五、CSS文件的代码分割
1. css文件代码分割
上面我们讲到了 js 文件如何进行代码分割现在我们来讲 css 文件如何进行代码分割。对于 css 文件的代码分割来说我们要引用到官方文档中提到的一个插件 MiniCssExtractPlugin 。接下来我们来看一下这个插件如何使用。
第一步 安装插件。具体命令如下
npm install --save-dev mini-css-extract-plugin第二步 在开发环境和线上环境中使用。我们打开 webpack.common.js 文件引入该插件并使用。具体代码如下
const MiniCssExtractPlugin require(mini-css-extract-plugin);module.exports {entry:{main: ./src/index.js},module:{rules:[{test:/\.scss$/,use:[MiniCssExtractPlugin.loader, {loader: css-loader,options: {//表明前面要先走sass-loader和postcss-loaderimportLoaders: 2,modules: true}}, sass-loader,postcss-loader]},{test:/\.css$/,use:[MiniCssExtractPlugin.loader,css-loader,postcss-loader]}]},plugins: [new MiniCssExtractPlugin({// 如果文件被直接引用走filenamefilename: [name].css,// 如果文件被间接的引用那么走chunkFilenamechunkFilename: [name].chunk.js})],optimization: {//使用treeShakingusedExports: true,splitChunks: {chunks: all,cacheGroups: {vendors: false,default: false}}}
}第三步 配置 package.json 文件。具体代码如下
{sideEffects: [//表示不对css文件开启treeShaking*.css]
}2. 压缩css文件
对于打包后的css文件其大小还是比较大的所以我们需要对文件大小进行压缩。这该怎么处理呢
**第一步**安装插件。具体命令如下
npm install optimize-css-assets-webpack-plugin -D第二步 在开发环境和线上环境中使用。我们打开 webpack.common.js 文件引入该插件并使用。具体代码如下
const CssMinimizerPlugin require(optimize-css-assets-webpack-plugin);module.exports {optimization: {minimizer: [new OptimizeCSSAssetsPlugin({})]}
}3. 合并打包css文件
有时候我们可能会有很多个入口文件每个入口文件又都有其对应的若干个 css 文件。那么这个时候我们想把所有的 css 文件都打包到同一个文件下该怎么处理呢
我们需要在 webpack.common.js 进行配置具体代码如下
module.exports {optimization: {splitChunks: {cacheGroups: {styles: {name: styles,test: /\.css$/,chunks: all,enforce: true,},},},}
}通过以上代码我们可以了解到我们需要在 splitChunks 中额外配置一个 styles 的 cacheGroups 将所有的 css 文件打包到一个 命名为 styles 的文件夹下。
六、webpack与浏览器缓存
1. 浏览器缓存配置
当我们刚访问网站时第一次加载总是需要从零开始加载各种文件的而假设我们的代码没有更新时我们希望再次加载时可以从浏览器中直接拉取缓存而不是重新进行加载。而等到我们的代码发生更新时再重新加载网页。那这该怎么处理呢
第一步 配置开发环境 webpack.dev.js 文件。具体代码如下
const devConfig {output: {filename: [name].js,chunkFilename: [name].chunk.js,}
}第二步 配置生产环境 webpack.prod.js 文件。具体代码如下
const prodConfig {output: {filename: [name].[contenthash].js,chunkFilename: [name].[contenthash].js,}
}以上的代码旨在解决的问题是当在线上环境时对输出的文件加一个哈希值。这个时候如果我们的代码有发生改变时webpack就会生成一个新的哈希值网页就会进行更新。如果我们的代码没有发生改变那么这个哈希值还是一样的不会改变网页就会从浏览器中拉取内存信息进行加载。
2. 解决旧版本问题
以上内容呢如果发生在一些比较低的 webpack 版本是不能生效的。所以我们需要进行一个配置来兼容低版本问题。我们在 webpack.common.js 下进行配置具体代码如下
module.exports {optimazation: {runtimeChunk: {name: runtime} }
}⚾七、Shimming的作用
1. Shimming垫片
继续现在我们来了解一下在 webpack 中 shimming 即垫片的概念。
在 webpack 的打包过程中呢我们往往要做一些代码上或者打包过程上的兼容。
比如对于两个 js 文件来说模块和模块之间是相互独立的他们之间是没有耦合度的。假设我们现在有两个文件具体代码如下
jquery.ui.js:
export function ui(){$(body).css(background, red);
}index.js:
import _ from lodash;
import $ from jquery;import { ui } from ./jquery.ui;ui();const dom $(div);
dom.html(_.join([Mondady, Tuesday]), ~);
$(body).append(dom);
大家可以看到现在我们想要在 index.ui.js 文件中引入 $ 但是在这个文件中它并没有引入 jquery 这个库。所以如果就这样子直接运行是肯定的会报错的。
因此如果我们想要解决这个问题该怎么进行配置呢
下面我们将对 webpack.common.js 进行配置。具体代码如下
const webpack require(webpack);module.exports {plugins: [new webpack.ProvidePlugin({$: jquery,//_: lodash,//_join: [lodash, join]})]
}所以这间接的可以理解为拿点东西把 $ 垫上也就有了我们标题说的 shimming 垫片的概念。
2. this指向
对于项目中的文件来说其 this 的指向都是指向模块本身而不是指向全局。那我们如果想让项目中的所有 js 文件都指向全局该怎么处理呢
第一步 安装 loader 。具体命令如下
npm install imports-loader --save-dev第二步 配置 webpack.common.js 。具体代码如下
module.exports {module: {rules: [{test: /\.m?js$/,exclude: /node_modules/,use: [{loader: babel-loader,},{loader: imports-loader?thiswindow}]}]}
}通过配置 imports-loader 以后 webpack 表明它将会把 js 文件中的 this 指向全部指向 window 全局中。
️八、结束语
在今天的文章中我们学习了使用 Tree Shaking 来优化代码的打包大小同时学习了 Dev 和 Prod 环境下的区分打包需要明确在这两个模式下各自相同的配置以及不同的配置分清楚他们之间的关系。
除此之外呢我们还学会了使用 webpack 来对 js 文件和 css 文件进行代码分割。以及使用 webpack 来对代码进行打包分析和提前加载 preloading 。
最后我们还学会了关于 webpack 如何开启浏览器缓存以及垫片 Shimming 的作用。
关于 webpack 的基础特性和高级特性讲到这里就结束啦希望对大家有帮助~
如有疑问或文章有误欢迎评论区留言或加vx: MondayLaboratory 交流~
本文代码已上传至公众号后台回复关键词 webpack 即可获取~
彩蛋 One More Thing
(往期推荐 webpack基础知识系列 vuejs基础知识系列
(番外篇 关注公众号星期一研究室第一时间关注优质文章更多精选专栏待你解锁~ 如果这篇文章对你有用记得留个脚印jio再走哦~ 以上就是本文的全部内容我们下期见