自字网站建设教程/seo信息优化
文章目录
- 前言
- webpack 核心包:
- 配置文件导出三种方式:
- 在线配置 webpack
- 配置文件解析:
- 入口(Entry):
- 输出(Output):
- 加载器(Loaders):
- 插件(Plugins):
- 模式(Mode):
- 目标(Target):
- webpack 的 runtime 和 manifest
- 服务器
- 模块解析配置
- 优化配置
- 热模块替换(Hot Module Replacement, HMR):
- 代码分割(Code Splitting):
- 在 Node 中使用 webpack
前言
Webpack 是一个现代 JavaScript 应用程序的静态
模块打包工具
,它可以将项目中的所有模块
(JavaScript、图片、CSS 等)打包成一个或多个 bundle
。
Webpack 4 是一个重要的版本,它提供了零配置、合理的默认设置、性能改进和开箱即用的优化工具。本文将对webpack 4
进行介绍,后面会对其他版本特性进行补充
webpack 核心包:
-
webpack: 这是 Webpack 的
核心包
,提供了模块打包的能力。它能够处理项目中 JavaScript 模块的依赖关系,并生成最终的静态资源文件。 -
webpack-cli: 这是 Webpack 的
命令行工具
,允许你通过命令行界面来运行 Webpack。它提供了各种命令来控制 Webpack 的构建过程。 -
webpack-dev-server: 这是一个小型的 Express
开发服务器
,用于开发环境。它提供了热模块替换(HMR)功能,允许在开发过程中实时重新加载模块,而无需刷新整个页面。
配置文件导出三种方式:
默认使用的是 webpack.config.js
文件,也可以是其他名字,webpack -c xxx
,只需要通过-c
置顶文件就行,配置文件默认有是三种导出格式:
- 对象或数组:单个配置或多个配置
- 函数: 可以根据环境变量和条件导出不同的配置
- Promise:用于远程加载其他配置参数,最终返回结果
代码实例:
// 对象或数组
module.exports = [{output: {filename: "./dist.js",},entry: "./app.js",},{output: {filename: "./dist-test.js",},entry: "./app.js",},
];
// 函数
module.exports = function (env, argv) {return {mode: env.production ? "production" : "development",devtool: env.production ? "source-map" : "eval",plugins: [new TerserPlugin({terserOptions: {compress: argv.mode === "production", // only if `--mode production` was passed},}),],};
};
// promise
module.exports = () => {return new Promise((resolve, reject) => {setTimeout(() => {resolve({entry: "./app.js",/* ... */});}, 5000);});
};
在线配置 webpack
- createapp.dev
配置文件解析:
入口(Entry):
- 入口点是应用程序的起点,Webpack 从这些点开始构建其依赖图。入口可以是一个文件或者一个文件数组。
// 单入口
entry: {main:'./index.js',
}
// 多入口
entry: {main: './src/app.js',foo: './src/foo.js',
},
输出(Output):
- 输出属性指定了打包后的文件将如何被写入到磁盘上。它定义了输出文件的名称、路径以及它们在浏览器中被引用的方式。
output: {filename: '[name].js', //hash选择:[hash],[contenthash] 或者 [chunkhash] 的长度可以使用 [hash:16]path: __dirname + '/dist', //输出目录publicPath: 'https://cdn.example.com/assets/[fullhash]/' // 设置cdn 和 hash},
加载器(Loaders):
- Webpack 只能理解 JavaScript,
Loaders 允许 Webpack 处理其他类型的文件
,并将它们转换为 Webpack 能够理解的模块【模块转化】
。 - loader 可以使你在 import 模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的得力方式
- loader 支持配置和内联的方式书写
- loader 执行顺序:
从右到左(或从下到上)
的执行(execute)
module: {rules: [{test: /\.css$/,exclude: /node_modules/,use: [{ loader: 'style-loader' },{loader: 'css-loader',options: {modules: true, // css模块化},},{ loader: 'sass-loader' },],},],}
插件(Plugins):
- 插件在 Webpack 构建过程中提供了更多的功能,如优化、压缩、分割代码等。插件可以在整个构建过程中的特定时机注入上下文。
- Webpack 内部广泛使用
Tapable
(一个 Node.js 库),它提供了一个发布-订阅(pub-sub)
机制,允许用户在特定的钩子(hook)上注册监听器(listener)。
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack"); // 访问内置的插件plugins: [new webpack.ProgressPlugin(),new HtmlWebpackPlugin({ template: "./src/index.html" }),
];
模式(Mode):
- 模式决定了 Webpack 是为开发环境还是生产环境构建应用程序。它可以是
development
、production
或none
。模式影响 Webpack 的优化和警告。
// 模式mode: 'production', //development
目标(Target):
用于告知 Webpack 为哪个环境或目标(target)进行构建编译 , 默认情况下,
target 的值是 "web"
// 模式target: 'web', //node、webworker 。。。。
webpack 的 runtime 和 manifest
- manifest 包含文件一般包含 ,如模块及模块依赖、每个模块的源码映射、异步加载的模块,等。
- runtime 会通过 manifest 来解析和加载模块。
服务器
配置开发服务器,包括代理、热模块替换等
devServer: {// 设置开发服务器监听的主机地址// '0.0.0.0' 表示服务器将接受所有可用网络接口的请求host: '0.0.0.0',// 设置开发服务器监听的端口号port: 3000,// 设置为 true 时,当 webpack 编译完成后,会自动在浏览器中打开应用open: true,// 启用模块热替换(HMR),允许在不刷新整个页面的情况下,实时更新模块hot: true,// 为单页应用(SPA)提供支持,当访问不存在的路由时,会返回 index.htmlhistoryApiFallback: true,// 开启 gzip 压缩,提高传输效率compress: true,// 指定了 public 目录下的文件作为静态资源// 当你访问如 /js/index.js 这样的路径时,devServer 会从 public 目录提供文件static: {directory: path.join(__dirname, 'public')},// 配置代理,用于开发环境的后端接口代理proxy: {// 当请求前缀为 /api 时,触发代理'/api': {// 代理目标服务器的地址target: 'http://backend.server.com',// 配置是否改变请求头中的origin字段changeOrigin: true,// URL 重写,这里将请求中的 /api 替换为空字符串 例如,将 /api/user 重写为 /userpathRewrite: { '^/api': '' },},},
},
模块解析配置
resolve: {alias: { //创建 import 或 require 的别名@: path.resolve(__dirname, 'src/'),_: path.resolve(__dirname, 'src/utils/'),},extensions: ['.js', '.jsx', '.ts','.tsx'], //尝试按顺序解析这些后缀名modules: [path.resolve(__dirname, 'src'), 'node_modules'], //告诉 webpack 解析模块时应该搜索的目录。},
优化配置
配置代码压缩、优化分割代码块。
// 优化optimization: {minimize:true, // 开启优化// minimizer 属性用于配置压缩工具,用于压缩 JavaScript 和 CSS 文件minimizer: [// TerserPlugin 是一个插件,用于压缩 JavaScript 文件new TerserPlugin({// terserOptions 用于传递给 Terser 的选项terserOptions: {// compress 属性用于配置压缩选项compress: {// drop_console 选项设置为 true,将删除所有的 console 语句drop_console: true}},// extractComments 选项设置为 false,以防止插件提取注释到单独文件extractComments: false}),// OptimizeCSSAssetsPlugin 用于压缩 CSS 文件new OptimizeCSSAssetsPlugin({})],// splitChunks 属性用于配置代码分割选项splitChunks: {// chunks 属性用于指定应该分割哪些 chunks,'all' 表示所有 chunkschunks: 'all',// minSize 属性定义了分割出的 chunk 的最小大小,这里是 20000 字节minSize: 20000,// minRemainingSize 属性定义了分割后剩余模块的最小大小,这里设置为 0minRemainingSize: 0,// minChunks 属性定义了模块应该被分割的最小 chunk 数量,这里是 1minChunks: 1,// maxAsyncRequests 属性定义了按需加载时的最大并行请求数,这里是 5maxAsyncRequests: 5,// maxInitialRequests 属性定义了初始加载时的最大并行请求数,这里是 3maxInitialRequests: 3,// automaticNameDelimiter 属性定义了自动生成的 chunk 名称之间的分隔符automaticNameDelimiter: '~',// automaticNameMaxLength 属性定义了自动生成的 chunk 名称的最大长度,这里是 30automaticNameMaxLength: 30,// cacheGroups 属性用于配置缓存组,用于更细致地控制代码分割cacheGroups: {// defaultVendors 缓存组用于处理来自 node_modules 的第三方库defaultVendors: {// test 属性用于定义哪些模块应该被包含在这个缓存组test: /[\\/]node_modules[\\/]/,// priority 属性定义了这个缓存组的优先级,-10 表示较低优先级priority: -10,// reuseExistingChunk 选项设置为 true,表示尽可能重用现有的 chunkreuseExistingChunk: true},// default 缓存组用于处理应用程序代码default: {// minChunks 属性定义了模块应该被分割的最小 chunk 数量,这里是 2minChunks: 2,// priority 属性定义了这个缓存组的优先级,-20 表示较低优先级priority: -20,// reuseExistingChunk 选项设置为 true,表示尽可能重用现有的 chunkreuseExistingChunk: true}}}
},
热模块替换(Hot Module Replacement, HMR):
- HMR 是一种功能,允许在应用程序运行时替换、添加或删除模块,而无需重新加载整个页面。
- 原理:
- 浏览器和服务器建立socket 通道
- 修改代码后,webpack compiler 发出
update
事件, - hmr 请求 manifest和chunk,根据页面内容配置,更新模块
// webpack.config.jsdevServer:{hot:true
}plugins: [new webpack.HotModuleReplacementPlugin()
]// component.jsfunction component() {const element = document.createElement('input');element.value = 123;return element;}let element = component();document.body.appendChild(element);if (module.hot) {module.hot.accept('./print.js', function() {console.log('热更新进入!');const value = document.getElementsByTagName("input")[0].value.value;element = component(); // 重新渲染 component 以更新点击事件处理程序document.body.appendChild(element);// 回显数据document.getElementsByTagName("input")[0].value.value = value})}
代码分割(Code Splitting):
- 代码分割是 Webpack 的一个特性,可以将代码分割成多个块,这些块可以按需加载或者并行加载,从而优化加载时间和性能。
- 代码拆分手段:import 动态导入、ensure方法、SplitChunksPlugin插件、多入口
- 动态导入(Dynamic Imports)
动态导入是实现代码分割最简单的方式之一。你可以使用 import()
函数来动态地加载模块。
// 1. 直接使用
if (someCondition) {import("./otherModule.js").then((otherModule) => {otherModule.doSomething();});
}// 2. promise 返回
function loadModule(modulePath) {return new Promise((resolve, reject) => {import(modulePath).then((module) => {resolve(module);},(err) => {reject(err);});});
}// 动态加载模块
loadModule("./otherModule.js").then((module) => {module.doSomething();}).catch((err) => {console.error("模块加载失败", err);});
在 Webpack 配置中,你不需要做任何特别的配置来处理动态导入,因为 Webpack 已经自动支持了。
- 使用
require.ensure
require.ensure
是一个更老的代码分割方法,require.ensure()
是 webpack 特有的,已被 import()
取代。。
// 参数1: dependencies 依赖数组
// 参数2: callback 回调函数
// 参数3: errorCallback: 失败回调
// 参数4: chunkName
// Webpack会创建一个名为 `feature` 的新chunk。
require.ensure([],() => {const module = require("./module");module.someFunction();},"feature"
);
- SplitChunksPlugin
SplitChunksPlugin
是 Webpack 4+ 引入的一个插件,用于控制代码块的分割逻辑。以下是一个基本的配置示例:
const webpack = require("webpack");module.exports = {// ...optimization: {splitChunks: {chunks: "all", // 代码分割的chunk类型,可选值有 'initial'、'async' 或 'all'minSize: 20000, // 最小chunk大小,默认单位是byteminChunks: 1, // 最小chunk数量,默认是1maxAsyncRequests: 5, // 按需加载时的最大并行请求数maxInitialRequests: 3, // 入口点的最大并行请求数automaticNameDelimiter: "~", // 分割出的chunk文件名的连接符cacheGroups: {defaultVendors: {test: /[\\/]node_modules[\\/]/,priority: -10,reuseExistingChunk: true,},default: {minChunks: 2,priority: -20,reuseExistingChunk: true,},},},},// ...
};
- 多入口拆分
如果你想要手动拆分第三方库,可以在 entry
属性中指定:
entry: {bundle: './src/index.js',vendor: ['react', 'react-dom'] // 将React和ReactDOM拆分出去
},output: {filename: '[name].js' // 根据entry的key来命名
},optimization: {splitChunks: {cacheGroups: {vendor: {test: /[\\/]node_modules[\\/]/,name: 'vendor',chunks: 'all'},},},
},
-
摇树优化(Tree Shaking):
- 摇树优化是一种去除应用程序中未引用代码的技术,通常与 ES6 模块一起使用。
-
懒加载(Lazy Loading):
- 懒加载是一种按需加载模块的技术,可以减少初始加载时间。
-
配置(Configuration):
- Webpack 的配置是通过一个名为
webpack.config.js
的文件来进行的,它定义了入口、输出、加载器、插件等。
- Webpack 的配置是通过一个名为
-
解析(Resolving):
- 解析是 Webpack 确定如何处理文件的过程,包括如何找到文件、如何解析文件中的模块请求等。
-
缓存(Caching):
- Webpack 通过缓存来提高构建性能,它会跳过未发生变化的模块,避免不必要的重新构建。
-
记录(Profiling):
- Webpack 可以生成构建的记录,帮助开发者分析和优化构建过程。
-
持久化(Persistence):
- Webpack 4 引入了持久化缓存,即使在构建之间也可以保持缓存状态。
在 Node 中使用 webpack
const webpack = require("webpack"); // 访问 webpack 运行时(runtime)
const configuration = require("./webpack.config.js");let compiler = webpack(configuration); //传入配置new webpack.ProgressPlugin().apply(compiler);compiler.run(function (err, stats) {if (err) {console.log("编译出错");}
});