文章目录
概要理解
vue或者react 通常用webpack作为打包工具,打包成浏览器识别的html、css、js -------简单理解webpack做为一个工厂。
- 需要告诉工厂先从那个入口(entry)开始去处理代码(通常是项目的main.js入口文件)
- 在所有的资源都间接或者直接被man,js引入之后,使用加载器(loaders) 将不同的原材料(less 、图片、css)转成javascript能理解的文件
- 当工厂还需要做一些特殊的处理(检查文件、代码压缩、图区css到单独的文件)的操作,这就是用来做特殊处理的工具(plugins)
- 那都处理好之后就需要输出了吧(output), webpack就将模块打包成一个或者多个文件,这些文件最终是浏览器运行的代码包
一、使用示例
首先先去webpack官方网站,包含了各种loader和plugins
1.引入库
npm install less less-loader --save-dev //处理less
npm install --save-dev css-loader //处理css
npm install --save-dev style-loader //处理style
npm install stylus stylus-loader --save-dev //处理stylus
npm i thread-loader -D
…
2.创建config/webpack.dev.js 测试环境
//创建config/webpack.dev.js 测试环境
//处理路径问题
const path = require("path");
//使用ESLintPlugin 来做文件检查(常用作团队开发 规范代码作用)
const ESLintPlugin = require("eslint-webpack-plugin");
//在打包之后的dist文件中 生成一个html根目录文件
const HtmlWebpackPlugin = require("html-webpack-plugin");
const os = require("os");
const threads = os.cpus().length; // 检查cpu核数 多进程打包
//工厂
module.exports = {
// 入口
entry: "./src/main.js", // 相对路径
// 输出
output: {
// 所有文件的输出路径
// 开发模式没有输出
path: undefined,//开发模式中 devserver会重新运行刷新
// 入口文件打包输出文件名
filename: "static/js/[name].js",
// 给打包输出的其他文件命名
chunkFilename: "static/js/[name].chunk.js",
// 图片、字体等通过type:asset处理资源命名方式
assetModuleFilename: "static/media/[hash:10][ext][query]",
},
// 加载器
module: {
rules: [
// loader的配置
{
// 每个文件只能被其中一个loader配置处理
//这样处理的好处 如果检测到是css 那么就不会往下走了,提高打包效率
oneOf: [
{
test: /\.css$/, // 只检测.css文件
use: [
// 执行顺序:从右到左(从下到上)
"style-loader", // 将js中css通过创建style标签添加html文件中生效
"css-loader", // 将css资源编译成commonjs的模块到js中
],
},
{
test: /\.less$/,
// loader: 'xxx', // 只能使用1个loader
use: [
// 使用多个loader
"style-loader",
"css-loader",
"less-loader", // 将less编译成css文件
],
},
{
test: /\.s[ac]ss$/,
use: [
"style-loader",
"css-loader",
"sass-loader", // 将sass编译成css文件
],
},
{
test: /\.styl$/,
use: [
"style-loader",
"css-loader",
"stylus-loader", // 将stylus编译成css文件
],
},
{
test: /\.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于10kb的图片转base64
// 优点:减少请求数量(降低服务器压力) 缺点:体积会更大
maxSize: 10 * 1024, // 10kb
},
},
//generator: {
// 输出图片名称
// [hash:10] hash值取前10位
//filename: "static/images/[hash:10][ext][query]",
//},
},
{
test: /\.(ttf|woff2?|map3|map4|avi)$/,
type: "asset/resource",
// generator: {
// 输出名称
// filename: "static/media/[hash:10][ext][query]",
//},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules下的文件,其他文件都处理
use: [
{
loader: "thread-loader", // 开启多进程
options: {
works: threads, // 进程数量
},
},
{
loader: "babel-loader",
options: {
// presets: ["@babel/preset-env"],
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
},
},
],
},
],
},
],
},
// 插件
plugins: [
// plugin的配置
new ESLintPlugin({
// 检测哪些文件
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存 意思就是说 每次打包 都要进行语句检查,那么缓存之前的,只检查修改的文件,提高性能
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/eslintcache"
),
threads, // 开启多进程和设置进程数量
}),
new HtmlWebpackPlugin({
// 模板:以public/index.html文件创建新的html文件
// 新的html文件特点:1. 结构和原来一致 2. 自动引入打包输出的资源
template: path.resolve(__dirname, "../public/index.html"),
}),
],
// 开发服务器: 不会输出资源,在内存中编译打包的
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
hot: true, // 开启HMR(默认值 意思是不会全部更新 哪里修改更新哪里 热更新除了js文件
},
optimization: {
// 开发模式下不需要压缩
// 代码分割配置
splitChunks: {
chunks: "all",
// 其他都用默认值
},
},
// 模式
mode: "development",
devtool: "cheap-module-source-map",
};
3.创建config/webpack.prod.js 正式环境
//创建config/webpack.prod.js 正式环境
//处理路径问题
const path = require("path");
//使用ESLintPlugin 来做文件检查(常用作团队开发 规范代码作用)
const ESLintPlugin = require("eslint-webpack-plugin");
//在打包之后的dist文件中 生成一个html根目录文件
const HtmlWebpackPlugin = require("html-webpack-plugin");
//将打包的css 处理成单独的css文件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
//将抽离出来的css 进行压缩
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const os = require("os");
const threads = os.cpus().length; // cpu核数 开启多进程打包
//压缩js
const TerserWebpackPlugin = require("terser-webpack-plugin");
//压缩图片
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
//预加载 浏览器空余时间 加载其他模块内容 提高性能
const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");
//断网了,但是页面还是会展示出来,离线缓存
const WorkboxPlugin = require("workbox-webpack-plugin");
// 用来获取处理样式的loader
function getStyleLoader(pre) {
return [
MiniCssExtractPlugin.loader, // 提取css成单独文件
"css-loader", // 将css资源编译成commonjs的模块到js中
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
pre,
].filter(Boolean);
}
module.exports = {
// 入口
entry: "./src/main.js", // 相对路径
// 输出
output: {
// 所有文件的输出路径
// __dirname nodejs的变量,代表当前文件的文件夹目录
path: path.resolve(__dirname, "../dist"), // 绝对路径
// 入口文件打包输出文件名
filename: "static/js/[name].[contenthash:10].js",
// 给打包输出的其他文件命名
chunkFilename: "static/js/[name].chunk.[contenthash:10].js",
// 图片、字体等通过type:asset处理资源命名方式
assetModuleFilename: "static/media/[hash:10][ext][query]",
// 自动清空上次打包的内容
// 原理:在打包前,将path整个目录内容清空,再进行打包
clean: true,
},
// 加载器
module: {
rules: [
// loader的配置
{
//这样处理的好处 如果检测到是css 那么就不会往下走了,提高打包效率
oneOf: [
{
test: /\.css$/, // 只检测.css文件
use: getStyleLoader(), // 执行顺序:从右到左(从下到上)
},
{
test: /\.less$/,
// loader: 'xxx', // 只能使用1个loader
use: getStyleLoader("less-loader"),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoader("sass-loader"),
},
{
test: /\.styl$/,
use: getStyleLoader("stylus-loader"),
},
{
test: /\.(png|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
// 小于10kb的图片转base64
// 优点:减少请求数量 缺点:体积会更大
maxSize: 10 * 1024, // 10kb
},
},
// generator: {
// 输出图片名称
// [hash:10] hash值取前10位
// filename: "static/images/[hash:10][ext][query]",
//},
},
{ //字体图标 其他资源文件 处理
test: /\.(ttf|woff2?|map3|map4|avi)$/,
type: "asset/resource",
//通过output统一输出
//generator: {
// 输出名称
//filename: "static/media/[hash:10][ext][query]",
//},
},
{
// 排除node_modules下的文件,将其他的js文件都做处理
//(因为浏览器虽然识别js文件,但是一些es6新语法
// 比如箭头函数、解构赋值依然没办法识别)所以使用babel转译代码
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: "thread-loader", // 开启多进程
options: {
works: threads, // 进程数量
},
},
{
loader: "babel-loader",
options: {
// presets: ["@babel/preset-env"],
cacheDirectory: true, // 开启babel缓存
cacheCompression: false, // 关闭缓存文件压缩
plugins: ["@babel/plugin-transform-runtime"], // 减少打包代码体积
},
},
],
},
],
},
],
},
// 插件
plugins: [
// plugin的配置
new ESLintPlugin({
// 检测哪些文件 (检查src下面所有的文件)
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值(除了node_modules)
cache: true, // 开启缓存 意思就是说 每次打包 都要进行语句检查,那么缓存之前的,只检查修改的文件,提高性能
cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache"), //缓存的地址
threads, // 开启多进程和设置进程数量
}),
new HtmlWebpackPlugin({
// 模板:以public/index.html文件创建新的html文件
// 新的html文件特点:1. 结构和原来一致 2. 自动引入打包输出的资源
//会在dist文件下创建一个一样index.html 并且以link标签方式,引入了output出口文件main.js文件
template: path.resolve(__dirname, "../public/index.html"),
}),
//在插件中 创建MiniCssExtractPlugin(将css文件抽出,并放到指定的目录下)
//打包后 会以link标签方式,在index.html,引入了main.css文件
//new MiniCssExtractPlugin({
//filename: "static/css/main.css",
//}),
//打包后 拆分为不同的css文件
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].chunk.[contenthash:10].css",
}),
// 将打包后css压缩
//new CssMinimizerPlugin(),
// 打包后js压缩
// new TerserWebpackPlugin({
// parallel: threads, // 开启多进程和设置进程数量
//}),
// 预获取/预加载模块 浏览器空闲时候 提前加载模块 提高加载性能
new PreloadWebpackPlugin({
// rel: "preload",
// as: "script",
rel: "prefetch",
}),
// 意思 假如断网了,但是页面还是会展示出来,离线缓存
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何“旧的” ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
],
//将js css 图片等 打包后的资源 进行压缩
optimization: {
// 压缩的操作
minimizer: [
// 压缩css
new CssMinimizerPlugin(),
// 压缩js
new TerserWebpackPlugin({
parallel: threads, // 开启多进程和设置进程数量
}),
// 压缩图片
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
],
// 代码分割配置
splitChunks: {
chunks: "all",
// 其他都用默认值
},
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}.js`,
},
},
// 模式
mode: "production",
devtool: "source-map",
};
3.创建eslintrc.js
//根目录下 eslintrc.js 需要在webpack.prod.js做相应配置
//在这个文件下 来自定义语法规范
module.exports = {
// 继承 Eslint 规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
parserOptions: {
ecmaVersion: 6, // es6
sourceType: "module", // es module
},
rules: {
"no-var": 2, // 不能使用 var 定义变量
},
plugins: ["import"], // 解决动态导入语法报错
};
4.创建babel.config.js
//根目录下 babel.config.js 需要在webpack.prod.js做相应配置
//(因为浏览器虽然识别js文件,但是一些es6新语法
// 比如箭头函数、解构赋值依然没办法识别)所以使用babel转译代码
// 配置智能预设(根据你所支持的浏览器或运行环境(如 Node.js)的版本,自动决定需要哪些 Babel 插件来转换代码)
module.exports = {
// 智能预设:能够编译ES6语法
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 按需加载自动引入
corejs: 3, //识别es6+新语法 补丁的作用 解决兼容性问题
},
],
],
};
5.package.json
{
"name": "web-pack-code",
"version": "1.0.0",
"description": "",
//测试环境下 输出文件
"main": "./src/main.js",
"scripts": {
//启动dev命令 令devserver重新刷新项目
//devserver 实际会打包,但是打包的会存储在内存中,不会写入到磁盘 中,让保存修改文件时,触发devserver会重新更新,并将结果存储到内存中。
"start": "npm run dev",
//这里测试环境入口 就是配置的webpack.dev.js
"dev": "webpack serve --config ./config/webpack.dev.js",
// 打包 使用配置的正式环境 打包成一个或者多个文件组合成的dist
"build": "webpack --config ./config/webpack.prod.js"
},
5.main.js
// 完整引入
// import 'core-js'
// 按需加载 识别es6+新语法 补丁的作用 解决兼容性问题
// import "core-js/es/promise";
if (module.hot) {
// 判断是否支持热模块替换功能
module.hot.accept("./js/count");
module.hot.accept("./js/sum");
}
//离线缓存
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/service-worker.js")
.then((registration) => {
console.log("SW registered: ", registration);
})
.catch((registrationError) => {
console.log("SW registration failed: ", registrationError);
});
});
}
总结
`未完 继续更新,有错误请留言 会及时改正