Webpack 5
Прошло много времени с момента выпуска, и леса, используемые в компании, по-прежнему являются версией v4.Я слышал, что основное внимание в обновлении версии v5 уделяется оптимизации производительности конфигурации. Звучит вкусно, хочу использоватьWebpack 5
Соберите стенд и посмотрите, как он себя чувствует в целом, потому что я в основном используюReact
развитие такReact
Например, для тех, кто не знаком с Webpack 5, можно прочитать эту статьюОценка начала работы с Webpack5, на самом деле содержимое конфигурации не сильно изменилось по сравнению с Webpack 4. Главное — это улучшение производительности, так что без лишних слов приступим.
Webpack 5
Требование к версии для Node.js — не ниже 10.13.0 (LTS).
Инициализация проекта
mkdir webpack5-demo
cd webpack5-demo
npm init -y
Установить базовые зависимости
Пакет, который нужно установить прямо сейчас, я вставлю его напрямую, вы можете скопировать его в файл package.json для выполненияnpm i 或 yarn
package.json
"devDependencies": {
"@babel/core": "^7.13.8",
"@babel/preset-env": "^7.13.8",
"@babel/preset-react": "^7.12.13",
"babel-loader": "^8.2.2",
"chalk": "^4.1.0",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^5.1.0",
"html-webpack-plugin": "^5.2.0",
"ip": "^1.1.5",
"style-loader": "^2.0.0",
"progress-bar-webpack-plugin": "^2.1.0",
"speed-measure-webpack-plugin": "^1.4.2",
"webpack": "^5.24.2",
"webpack-cli": "^4.5.0",
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
Ситуация с файловым каталогом в настоящее время
webpack5-demo
├─ node_modules
├─ package-lock.json
└─ package.json
настроить веб-пакет
Для того, чтобы различать среды развития и производства, простое обслуживание и специальное лечение, чтобы не поместить все конфигурацию контентаwebpack.config.js
в этом файле.
# 这里我们新建一个 config 目录用来专门存放 webpack 配置文件
mkdir config
cd config
touch webpack.common.js # 开发环境 和 生产环境 公共配置 存放在这个文件里面
touch webpack.dev.js # 需要针对开发环境特殊处理的配置存放在这里
touch webpack.prod.js # 需要针对生产环境特殊处理的配置存放在这里
При настройке Webpack неизбежно иметь дело с путем к файлу, чтобы избежать запутанных путей, и создать файл конфигурации, вызываемый путем отдельно, что также относится к CRA.
touch paths.js
paths.js
const path = require("path");
const fs = require("fs");
// 获取当前工作目录
const appDirectory = fs.realpathSync(process.cwd());
// 从相对路径中解析绝对路径
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
// 默认的模块扩展名
const moduleFileExtensions = ["js", "jsx", "ts", "tsx", "json"];
// 解析模块路径
const resolveModule = (resolveFn, filePath) => {
// 查看文件存不存在
const extension = moduleFileExtensions.find((extension) =>
fs.existsSync(resolveFn(`${filePath}.${extension}`))
);
if (extension) {
return resolveFn(`${filePath}.${extension}`);
}
return resolveFn(`${filePath}.js`); // 如果没有默认就是js
};
module.exports = {
appBuild: resolveApp("build"), // 打包路径
appPublic: resolveApp("public"), // 静态资源路径
appHtml: resolveApp("public/index.html"), // html 模板路径
appIndexJs: resolveModule(resolveApp, "src/index"), // 打包入口路径
appNodeModules: resolveApp("node_modules"), // node_modules 路径
appSrc: resolveApp("src"), // 主文件入口路径
moduleFileExtensions, // 模块扩展名
};
Ситуация с файловым каталогом в настоящее время
demo
├─ config
├─ paths.js
│ ├─ webpack.common.js
│ ├─ webpack.dev.js
│ └─ webpack.prod.js
├─ node_modules
├─ package-lock.json
└─ package.json
webpack.common.js
const paths = require("./paths");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = function (options) {
return {
mode: options.mode,
entry: paths.appSrc,
output: {
path: paths.appBuild,
publicPath: "/",
},
cache: {
// 使用持久化缓存
type: "filesystem", //memory:使用内容缓存 filesystem:使用文件缓存
},
devtool: false,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: [
"@babel/preset-env",
"@babel/preset-react",
],
},
},
],
},
],
},
devServer: {},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
...options.plugins,
],
stats: options.stats, // 打包日志发生错误和新的编译时输出
};
};
запись - это запись, путь поиска по умолчанию - это то, что мы написали, здесь нам нужно предоставить файл записи
# 回到webpack5-demo 根目录
# 创建一个src 目录开发文件
mkdir src
touch index.js # 创建一个入口文件
import React from "react";
import ReactDOM from "react-dom";
const App = () => {
return <div> App入口 </div>;
};
ReactDOM.render(<App />, document.querySelector("#root"));
При упаковке используйтеHtmlWebpackPlugin
, поэтому вам нужно создать html-шаблон, чтобы предоставить достаточно плагинов для использования
# 回到webpack5-demo 根目录
# 创建一个public 目录专门存放 静态资源
mkdir public
touch index.html # 创建一个html 模板
шаблон index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Webpack-React-Cli</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Конфигурация разработки webpack.dev.js
module.exports = require("./webpack.common")({
mode: "development",
plugins: [],
stats: "errors-only", //只在发生错误或有新的编译时输出
});
рабочая конфигурация webpack.prod.js
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); //打包前清空build目录文件
const ProgressBarPlugin = require("progress-bar-webpack-plugin"); // 打包进度条美化
const chalk = require("chalk");
module.exports = require("./webpack.common")({
mode: "production",
devtool: "source-map",
plugins: [
new CleanWebpackPlugin(),
new ProgressBarPlugin({
format:
`${chalk.green.bold("build[:bar]")} ` +
chalk.green.bold(":percent") +
" (:elapsed seconds)",
clear: false,
width: 60,
}),
],
stats: "normal", //标准输出
});
Ситуация с файловым каталогом в настоящее время
webpack5-demo
├─ config
│ ├─ paths.js
│ ├─ webpack.common.js
│ ├─ webpack.dev.js
│ └─ webpack.prod.js
├─ node_modules
├─ public
│ └─ index.html
├─ src
│ └─ index.js
├─ package-lock.json
└─ package.json
запустить службу
Теперь нашWebpack
Базовая конфигурация в порядке, она вот-вот начнется
Настройте скрипт pageage.json
{
"name": "webpack5-demo",
"version": "1.0.0",
"description": "基于webpack5 的React架手架",
"main": "index.js",
"scripts": {
"build": "webpack --config config/webpack.prod.js",
"start": "webpack serve --config config/webpack.dev.js", // v5
"dev": "webpack-dev-server --config config/webpack.dev.js" //v4
},
"keywords": [],
"author": "Jason",
"license": "ISC",
...
}
Небольшое изменение здесь:
существуетWebpack 4
пройти внутрьwebpack-dev-server
оказание услуг
существуетWebpack 5
Внутри запустите службу черезwebpack serve
Сейчас он был успешно запущен, но мне не очень нравится этот журнал запуска, мне нужно его преобразовать (чтобы реализовать собственное содержимое компиляции вывода), и мне нужно перенастроить сервер разработки (webpack-dev-server)
Настроить сервер разработки
Хотя рекомендуется пройтиCLI
бегатьwebpack-dev-server
, но мы также можем выбрать запуск сервера через API.
# 回到webpack5-demo 根目录
# 创建一个server目录
mkdir server
touch index.js # 服务入口
touch appConfig.js # 基础服务配置 自定义服务端口,ip, 代理地址
touch logger.js # 控制台输出的日志
appConfig.js
module.exports = {
deployUrl: "127.0.0.0:8080", // 本地代码推推送到指定服务器
proxyUrlMap: {
"/api": "localtion:3000", // 代理的接口
"/api2": "localtion:4000", // 代理的接口
},
port: 9000, //端口号,
host: "localhost", //主机号
};
logger.js
const ip = require("ip");
const divider = chalk.gray("\n-----------------------------------");
const logger = {
error: (err) => {
console.error(chalk.red(err));
},
appStarted: (port, host, tunnelStarted) => {
console.log(`Server started ! ${chalk.green("✓")}`);
if (tunnelStarted) {
console.log(`Tunnel initialised ${chalk.green("✓")}`);
}
console.log(`
${chalk.bold("Access URLs:")}${divider}
Localhost: ${chalk.magenta(`http://${host}:${port}`)}
LAN: ${
chalk.magenta(`http://${ip.address()}:${port}`) +
(tunnelStarted
? `\n Proxy: ${chalk.magenta(tunnelStarted)}`
: "")
}${divider}
${chalk.blue(`Press ${chalk.italic("CTRL-C")} to stop`)}
`);
},
};
module.exports = logger;
index.js
const Webpack = require("webpack");
const WebpackDevServer = require("webpack-dev-server");
// webpack开发 配置文件
const webpackConfig = require("../config/webpack.dev");
// 自定义日志输出
const logger = require("./logger");
// 服务配置
const appConfig = require("./appConfig");
const { port, host } = appConfig; // 监听的端口号
//编译器
const compiler = Webpack(webpackConfig);
// devServer 参数
const devServerOptions = Object.assign({}, webpackConfig.devServer, {
// open: true, // 自动打开浏览器
compress: true, // gzip 压缩
stats: "minimal",
});
const server = new WebpackDevServer(compiler, devServerOptions);
server.listen(port, host, async (err) => {
if (err) {
return logger.error(err.message);
}
logger.appStarted(port, "localhost");
});
существуетpackage.json
Настроить команды запуска
"scripts": {
"build": "webpack --config config/webpack.prod.js",
"start": "node server"
},
Ситуация с файловым каталогом в настоящее время
webpack5-demo
├─ config
│ ├─ paths.js
│ ├─ webpack.common.js
│ ├─ webpack.dev.js
│ └─ webpack.prod.js
├─ node_modules
├─ public
│ └─ index.html
├─ server
│ ├─ appConfig.js
│ ├─ index.js
│ └─ logger.js
├─ src
│ └─ index.js
├─ package-lock.json
└─ package.json
решить
resolve
Вы можете настроить следующее, а остальные можно использовать по умолчанию.
- модули: используйте первую реакцию третьего модуля, чтобы перейти к node_modules в корневом каталоге, чтобы найти
- расширения: в
import
Когда расширение файла не добавлено, оно будет пройдено по очередиextensions
добавить расширение для соответствия - псевдоним: создайте псевдоним, в
import
илиrequire
псевдонимы для облегчения импорта модулей
resolve: {
modules: [paths.appNodeModules],
extensions: ['.js', '.jsx', '.css'],
alias: {
moment$: 'moment/moment.js',
'@src': paths.appSrc,
'@public': paths.appPublic,
},
},
Базовая конфигурация загрузчика
css и сасс
Установить
npm i -D style-loader css-loader
npm i -D node-sass sass-loader postcss postcss-loader postcss-preset-env
Конфигурация загрузчика css и sass очень проста Учитывая проблемы совместимости, postcss-loader также должен добавить заголовок логотипа производителя браузера.
Используемые плагины размещаются в корневом каталоге отдельноpostcss.config.js
в файле конфигурации
postcss.config.js
module.exports = {
plugins: {
"postcss-preset-env": {},
},
};
Ресурсы модуля
Webpack 4
Он используется при обработке изображений или текстовых файлов.file-loader
илиurl-loader
теперь дляWebpack 5
может быть использованAsset Modules
(ресурсный модуль), нет необходимости настраивать загрузчик
- актив/источник экспортировать исходный код актива (эквивалентно необработанному загрузчику)
- Актив / ресурс отправляет один файл и экспортирует URL-адрес (эквивалентный файловой загрузчике)
- актив/встроенный экспортирует URI данных актива (эквивалентно url-loader)
- актив автоматически выбирает между экспортом URI данных и отправкой отдельного файла, что ранее достигалось с помощью url-loader и настройки ограничений размера актива.
// 设置 常量
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const imageInlineSizeLimit = 4 * 1024;
module.exports = function (options) {
return {
...
module: {
rules: [
{
oneOf: [
...
{
test: cssRegex,
exclude: cssModuleRegex,
use: ['style-loader', {
loader: 'css-loader',
options: {
importLoaders: 1 // 0 => 无 loader(默认); 1 => postcss-loader; 2 => postcss-loader, sass-loader
}
},'postcss-loader'],
},
{
test: sassRegex,
exclude: sassModuleRegex,
use: ['style-loader', {
loader: 'css-loader',
options: {
importLoaders: 1 // 查询参数 importLoaders,用于配置「css-loader 作用于 @import 的资源之前」有多少个 loader
}
}, 'postcss-loader', 'sass-loader'],
},
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: imageInlineSizeLimit // 4kb
}
}
},
{
test: /\.(eot|svg|ttf|woff|woff2?)$/,
type: 'asset/resource'
},
]
}
]
},
}
Протестируйте css и изображения
# 在src 目录下新一个 style.scss 文件
touch style.scss
Сначала напишите что-нибудь
* {
margin: 0;
padding: 0;
}
div {
color: red;
}
Импорт стилей и изображений
import React from "react";
import ReactDOM from "react-dom";
import npm from "@public/assets/imgs/npm.png";
import "./style.scss";
const App = () => {
return (
<div>
App入口
<img src={npm} />
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
Проверьте упаковку
Второй раз быстрый из-за установленного постоянного кеша
Ситуация с файловым каталогом в настоящее время
webpack5-demo
├─ build
├─ config
│ ├─ paths.js
│ ├─ webpack.common.js
│ ├─ webpack.dev.js
│ └─ webpack.prod.js
├─ node_modules
├─ public
│ ├─ assets
│ │ └─ imgs
│ │ └─ npm.png
│ └─ index.html
├─ server
│ ├─ appConfig.js
│ ├─ index.js
│ └─ logger.js
├─ src
│ ├─ index.js
│ └─ style.css
├─ package-lock.json
└─ package.json
резюме
Контента еще много и я планирую написать его в двух частях, первая часть пока относительно простая. Вторая статья более оптимизирована, оптимизирована под новые возможности вебпака 5, настройку спецификации кода eslint, использование некоторых плагинов, а так же хочу попробовать написать статьи, посмотрите как первый черновик, больше 50 лайков пишите Один (Хахаха О(∩_∩)О)