webpack@5 与脚手架开发
1 webpack 基础介绍
- 项目构建工具
- 可以打包所有的项目资源 脚本 图片 样式
- .hbs:模板文件
- .cjs:commonjs 规范的文件
- …
- 打包成浏览器可以识别的文件
- .css,.js,.png,.jpg
2 webpack 的基本使用
- 安装 webpack
- 在开始之前,确保安装了 nodejs 的最新版本
- 本地安装 :
npm install webpack webpack-cli --save-dev
- 确保使用的是最新的 5.x.x 版本
- webpack 的配置文件
- 项目根目录:
webpack.config.js
- 项目根目录:
package.json
- 在 script 选项添加一个键值对
- 项目根目录:
- 项目源代码:src 目录
- 在 src 中创建一个入口文件 main.js
- 运行开发调试命令
npm start
// webpack.config.js
const path = require("path");
// 导入html-webpack-plugin插件
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// 这里面就是配置项
// 入口: 让webpack直到我们项目的从哪里开始打包
// 单入口
entry: path.resolve(__dirname, "src/main.js"),
// 出口: 让webpack知道我们项目打包以后放在那个文件夹下面以及打包好的文件叫什么名字
output: {
path: path.resolve(__dirname, "dist"), // 项目打包以后放在那个文件夹下面
filename: "bundler.js", // 打包好的文件叫什么名字
},
// 模式:告诉webpack本次打包的用户是为了开发调试还是交给后端部署上线
mode: "development", // 本次打包是为了开发调试
// 插件:把打包好的dist/bundler.js 引入到index.html中
plugins: [
// 可以用好多的插件,所有是数组
// HtmlWebpackPlugin可以帮我简单创建html文件,并把打包好的js引入
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src/index.html"),
}),
],
};
// package.json
// ....
"scripts": {
"start": "webpack --config webpack.config.js"
}
// ....
3 配置项 output
- 定义 webpack 打包输出的目录和文件名
- output.clean : 打包之前清空原来的输出目录
- ‘[name]’:入口名称
- ‘[hash]’: 项目唯一的 hash 生成,可以通过[hash:5]指定 hash 长度为 5,默认 20
- ‘[id]’:内部 chunk id
- ‘[chunkhash]’:基于每一个 chunk 内部的 hash,可以通过[chunkhash:5]指定 hash 长度为 5,默认 20
4 配置项 entry
- 定义 webpack 打包的入口
- 单入口
// 单入口,单输出文件
entry: path.resolve(__dirname, "src/main.js"), // 路径是一个字符串
- 多入口, 单输出文件
// 单入口,单输出文件
entry:[ path.resolve(__dirname, "src/main.js"), path.resolve(__dirname, "src/fisrt.js")], // 路径是一个字符串的数组
- 多入口,多输出文件
// 多入口,多输出文件
// 多个chunk是插入同一个html文件还是分别插入多个html文件
// 由HtmlWebpackPlugin来进行配置,默认是插入同一个html文件
entry:{
// "chunk name":"入口文件路径"
'app':path.resolve(__dirname, "src/fisrt.js"),
'main':path.resolve(__dirname, "src/main.js")
}
- 多页面的 HtmlWebpackPlugin 配置
plugins: [
// 多入口,多页面配置,一定要有filename设置,否则会报错
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src/index.html"),
filename: "app.html",
chunks: ["app"],
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src/index.html"),
filename: "main.html",
chunks: ["main"],
}),
];
5 管理资源:loader 用于加载(处理)各种各样的资源
5.1 加载 css
- 方法 1: 把解析好的 css 插入 style 这个 dom 里面
- 使用 css-loader 和 style-loader 来解析 css 文件
- 先安装:
npm install css-loader style-loader -D
- 通过配置 webpack.config.js 的 module 里面的 rules 来处理 css 文件
module: {
rules: [
// 一条规则对应一种资源
{
// 告诉规则,后缀是.css的文件用我处理
test: /\.css$/,
// 指定要应用的loaders
// use后面的数组里面书写loader的名称
// loader有使用的先后顺序,现在后面的先执行
// 要使用loader要先安装
use: ["style-loader", "css-loader"],
// 当webpack工作的时候,遇到.css结尾的资源
// 使用css-loader进行加载和解析成css代码
// 交给style-loader插入到index.html的style标签中
},
],
}
- 方法 2:把 css 代码生成单独的文件
- 使用 css-loader 和 mini-css-extract-plugin
- 先安装:
npm install css-loader mini-css-extract-plugin -D
- 通过配置 webpack.config.js 的 module 里面的 rules 来处理 css 文件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
// ...
module: {
rules: [
// 一条规则对应一种资源
{
// 告诉规则,后缀是.css的文件用我处理
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
// 当webpack工作的时候,遇到.css结尾的资源
// 使用css-loader进行加载和解析成css代码
// 交给MiniCssExtractPlugin.loader变成单独的css文件
},
],
},
plugins: [
// ...,
new MiniCssExtractPlugin({
filename: "css/[name].[chunkhash:5].js", // 把生成的css文件通过link插入html页面中
}),
],
// ...
};
5.2 加载 sass
- 把 sass 代码生成单独的 css 文件
- 使用 sass-loader,css-loader 和 mini-css-extract-plugin
- 由于 sass-loader 内部依赖 node-sass,所以 node-sass 也要一起安装
- 先安装:
npm install node-sass sass-loader -D
- 通过配置 webpack.config.js 的 module 里面的 rules 来处理 sass 文件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
// ...
module: {
rules: [
// 一条规则对应一种资源
{
// 告诉规则,后缀是.css的文件用我处理
test: /\.(css|sass|scss)$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
// 当webpack工作的时候,遇到.css或者.sass或者.scss结尾的资源
// 使用sass-loader加载
// 使用css-loader进行加载和解析成css代码
// 交给MiniCssExtractPlugin.loader变成单独的css文件
},
],
},
plugins: [
// ...,
new MiniCssExtractPlugin({
filename: "css/[name].[chunkhash:5].js", // 把生成的css文件通过link插入html页面中
}),
],
// ...
};
5.3 加载 img
- 加载 js 中的图片和 css 中的图片
- html 中的图如果也需要处理需要使用 html-loader
- 一般 html 中的图片不处理
module.exports = {
module: {
rules: [
//...
{
test: /\.(png|jpg|gif|jpeg|svg)$/,
type: "asset/resource",
generator: {
filename: "img/[name].[hash:5][ext]",
},
},
// [name]:图片的原始名称
// [ext]: 图片的原始后缀名
//...
],
},
};
5.3 编译代码
编译目标 1:加载 ES2015+ 代码,然后使用 Babel 转译为 ES5
- 使用的 loader:
babel-loader
babel-loader
内部依赖 babel 的核心包:@babel/core
- 是否所有语法都需要转成 es5 语法取决于你的项目要在哪些浏览器上运行
- 可以在 package.json 中通过 browerslist 来设置项目要运行的浏览器版本
- 可以在 babel 的配置文件中来设置项目要运行的浏览器版本
- babel 的配置文件可以放在项目根目录的 babel.config.js
- babel 的配置文件可以放在 babel-loader 的 options 中
- babel 的配置文件可以放在 package.json 的 babel 选项中
- 要使用 babel-loader,先安装包
npm install @babel/core babel-loader @babel/preset-env
- 第一步:先书写项目要适配的浏览器
- 在 package.json 添加
{
// ...
"browserslist": [
">0.25%",
"not dead"
]
}
- 第二步:
- 写法 1:在 webpack.config.js 的 module 的 rules 里面添加一个新的转换编译代码的规则
module.exports = {
// ..
module: {
rules: [
// ....,
{
test: /\.js$/, // 处理js后缀的文件转换
exclude: /node_modules/, // 排除node_modules里面的js文件
use: [
{
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", {}]],
// {}里面可以通过targets设置想要要适配的浏览器
// 由于前面在package.json设置了,这里就设置为{}
},
},
],
},
],
},
};
- 写法 2:在 webpack.config.js 的 module 的 rules 里面添加一个新的转换编译代码的规则
module.exports = {
// ..
module: {
rules: [
// ....,
{
test: /\.js$/, // 处理js后缀的文件转换
exclude: /node_modules/, // 排除node_modules里面的js文件
use: ["babel-loader"],
},
],
},
};
- 把 babel 的设置放在单独的 babel.config.js 文件中
// babel.config.js
presets: [["@babel/preset-env", { targets: "defaults" }]];
编译目标 2:加载 JSX 代码
-
用 babel-loader 来处理 jsx 文件
-
修改 webpack.config.js 的配置
module.exports = {
// ...
module: {
rules: [
// 转换编译
{
test: /\.(js|jsx)$/, // 处理js后缀的文件转换
exclude: /node_modules/, // 排除node_modules里面的js文件
use: ["babel-loader"],
},
],
},
};
- 添加新的用于处理 jsx 的预设集
- 安装:
npm install @babel/preset-react -D
- 配置 babel 使用这个预设集,在 babel.config.js
// babel.config.js
module.exports = {
presets: [
["@babel/preset-env", { targets: "defaults" }],
["@babel/preset-react", {}],
],
};
- 就可以写 jsx 代码了
- 把 main.js 改成了 main.jsx,顺便把入口也修改成 main.jsx
- jsx 是写 react 的,安装:
npm install react react-dom -S
// main.jsx
// 要用jsx语法,要先安装react
import React from "react";
// 要渲染dom,要先安装react-dom
import { createRoot } from "react-dom/client";
const ele = <h1>hello world</h1>;
// 把id是app的元素变成react的根节点
const root = createRoot(document.getElementById("app"));
// 在里面渲染ele这个html结构
root.render(ele);
- 上面写完就可以编译转换了,但是,main.jsx 打包以后体积太大,而且里面大部分是第三方 react 包
- 我们打算把第三方包抽取成一个单独的 js 文件
- 修改 webpack.config.js 的入口文件
module.exports = {
entry: {
// 把react等第三包放在一个入口里面
venders: ["react", "react-dom"],
app: {
import: path.resolve(__dirname, "src/main.jsx"),
dependOn: "venders", // 表示app里面import的文件要依赖venders入口的js代码
},
},
};
6 配置别名
// webpack.config.js
module.exports = {
// ...
resolve: {
// 配置别名
alias: {
"@": path.resolve(__dirname, "src"),
},
// 允许忽略后缀名
extensions: [".js", ".jsx", "json"],
// 指定寻找第三方包的位置
modules: ["node_modules"],
},
};
8 开启热更新服务器
- 安装:
npm install webpack-dev-server -D
- 在 webpack.config.js 里面添加配置
module.exports = {
// ...
// 配置热更新服务器
devServer: {
// 设置服务器的根目录
static: path.resolve(__dirname, "dist"),
// 服务器端口
port: 8000,
// 是否自动打开浏览器
open: true,
// 用gzip压缩和提供服务
compress: true,
},
};
- 在 package.json 的 scripts 里面配置一个新的开启服务器的命令
{
// ...
"scripts": {
"start": "webpack --config webpack.config.js",
"dev": "webpack-dev-server --config webpack.config.js"
},
}
- 开发热更新服务器命令:
npm run dev