背景
收集整理了一波webpack常见题型,文章内容参考了多个大佬的博客,链接已放。同时,加上自己的理解,简单总结一波。如有错误,欢迎指教。
webpack整体原理说明
Tree Shaking
zhuanlan.zhihu.com/p/127804516 juejin.cn/post/695538…
借助静态模块分析,Tree-Shaking 实现的大体思路:借助 ES6 模块语法的静态结构,通过编译阶段的静态分析,找到没有引入的模块并打上标记,然后在压缩阶段利用像 uglify-js 这样的压缩工具删除这些没有用到的代码。
副作用
有副作用,就是不能被shaking删除,没有副作用,就是可以被删除。 配置sideEffects:false,就代表所有都没有副作用
一个副作用是:有一些代码,是在 import 时执行了一些行为,这些行为不一定和任何导出相关。例如 polyfill ,Polyfills 通常是在项目中全局引用,而不是在 index.js 中使用导入的方式引用。
Tree Shaking 并不能自动判断哪些脚本是副作用,因此手动指定它们非常重要
要将某些文件标记为副作用,我们需要将它们添加到package.json文件中。
{
...,
"sideEffects": [
"./src/polyfill.js"
],
...,
}
或者在函数的左侧添加注释
/*#__PURE__*/ double(55);
按需加载
import()时可以通过注释语法import(/chunkName/'qqapi').then()来定义异步加载模块打包出来的chunkName,否则会默认以id作为chunkName
按需加载主要分为两种:
1.组件库按需加载:
组件库以组件为基本单位产出 js、css、less 文件,借助插件或者部分引入的写法,使得项目代码或 babel 编译后的代码中只包含使用到的组件的 js、css、less 等
2.webpack 懒加载:
webpack 将源码中的 import、require 引入的文件编译之后再根据动态加载语法配置(通常以页面路由为基本单位)将较大的代码拆分并构建出较小的 chunk 包,应用在运行时执行到相应业务逻辑时才去加载执行对应 chunk 代码。 webpack 懒加载主要发生在下图的 JS 拆分出不同的 Chunk 这一过程
可见,两者的差别主要在于:
两者执行时机不同,组件库按需加载是在源码编写阶段或者 babel 编译 js 阶段,而 webpack 懒加载则是在构建生成打包产物时,组件库按需加载在前,webpack 懒加载在后; 两者原理不同,组件库按需加载是在源码阶段就去掉了无关代码,而 webpack 懒加载则是将经过 tree-shaking 优化过后的大文件包进行拆分在适当的运行时进行按需加载。
作者:dino小恐龙 链接:juejin.cn/post/696850… 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相同引入模块合并打包
webpack.docschina.org/guides/code… 配置 dependOn option 选项,这样可以在多个 chunk 之间共享模块:
配置entry,dependOn属性
const path = require('path');
module.exports = {
mode: 'development',
entry: {
index: './src/index.js',
another: './src/another-module.js',
index: {
import: './src/index.js',
dependOn: 'shared',
},
another: {
import: './src/another-module.js',
dependOn: 'shared',
},
shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
单独打包页面 打包多个页面
survivejs.com/webpack/out… To generate multiple pages with webpack, we can leverage mini-html-webpack-plugin. html-webpack-plugin would work well for the purpose as well and using it would give you access to the plugins written for it. For the demonstration, using the former is enough.
A page should receive title, url, and chunks for deciding which scripts to include to the page. The idea can be modeled as a configuration part as below:
// webpack.parts.js
const {
MiniHtmlWebpackPlugin,
} = require("mini-html-webpack-plugin");
exports.page = ({ title, url = "", chunks } = {}) => ({
plugins: [
new MiniHtmlWebpackPlugin({
publicPath: "/",
chunks,
filename: `${url && url + "/"}index.html`,
context: { title },
}),
],
});
// webpack.multi.js
const { merge } = require("webpack-merge");
const parts = require("./webpack.parts");
module.exports = merge(
{ mode: "production", entry: { app: "./src/multi.js" } },
parts.page({ title: "Demo" }),
parts.page({ title: "Another", url: "another" })
);
如何实现loader
webpack.docschina.org/contribute/… juejin.cn/post/684490…
// syncloader.ja
module.exports = function (source) {
console.log('source>>>>', source)
// source是源码,可以直接修改源码加注释
source += '// 升值加薪'
return source
}
const path = require('path')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
resolveLoader: {
// loader路径查找顺序从左往右
// 这里必须加,不然会找不到
modules: ['node_modules', './']
},
module: {
rules: [
// 这里也要配置具体使用的loader
{
test: /\.js$/,
use: 'syncLoader'
}
]
}
}
实现plugin
首先应该明确的是,plugin应该是一个类。 一般都是new Plugin()这种形式使用 webpack 插件是一个具有 apply 方法的 JavaScript 对象。apply 方法会被 webpack compiler 调用,并且在 整个 编译生命周期都可以访问 compiler 对象。 webpack.docschina.org/concepts/pl…
比如说,生成1个readme
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('webpack 构建正在启动!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
class DemoWebpackPlugin {
constructor () {
console.log('plugin init')
}
// compiler是webpack实例
apply (compiler) {
// 一个新的编译(compilation)创建之后(同步)
// compilation代表每一次执行打包,独立的编译
compiler.hooks.compile.tap('DemoWebpackPlugin', compilation => {
console.log(compilation)
})
// 生成资源到 output 目录之前(异步)
compiler.hooks.emit.tapAsync('DemoWebpackPlugin', (compilation, fn) => {
console.log(compilation)
compilation.assets['index.md'] = {
// 文件内容
source: function () {
return 'this is a demo for plugin'
},
// 文件尺寸
size: function () {
return 25
}
}
fn()
})
}
}
module.exports = DemoWebpackPlugin
感谢阅读,欢迎指教