Для квалифицированного фронтенд-разработчика завершение разработки бизнес-функций по требованию является лишь базовым требованием. Отличная база для инженеров и старших интерфейсных инженеров.
Что такое webpack, я не буду здесь больше объяснять, если вы не знаете, то эта статья не подходит вам для чтения сейчас.
ссылка на веб-пакет, не забудьте зайти и продолжить чтение после прочтения
базовая конфигурация webpack5
Давайте сначала рассмотрим базовую конфигурацию, файл webpack.config.js, основанный на webpack5.
/*
* webpack.config.js
*/
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// 模式
mode: "development",
// 入口
entry: "./src/index.js",
// 出口
output: {
filename: "built.js",
path: resolve(__dirname, "build"),
// 自定义输出 静态资源文件名(图片)
assetModuleFilename: "assets/[hash][ext]",
},
// 模块
module: {
rules: [
// loader的配置
{
test: /\.css$/,
// 使用loader对文件进行处理
/**
* use数组中的执行顺序是 从右到左 从下到上 依次执行
* style-loader 创建style标签,将样式文件引入到header中
* css-loader 将css模块变成commonjs模块加载到js中, 文件内容是样式字符串
*/
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
// 将less文件编译成css文件
// 需要下载 less-loader和less
"less-loader",
],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
// webpack 5 内置了资源类型,已经废弃了之前的 url-loader 和 file-loader
type: "asset/resource",
},
{
test: /\.html$/,
// 处理html中的图片文件 引入img文件进而让url-loader处理
loader: "html-loader",
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource",
},
],
},
// 插件
plugins: [
// HtmlWebpackPlugin
// 默认会创建一个空的html文件,会自动引入打包完成的所有资源。
// 需要有结构的html文件
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
/**
* 下载 yarn add webpack-dev-server --dev
* 运行 npx webpack serve
*/
devServer: {
// 项目构建后的路径
contentBase: resolve(__dirname, "build"),
// 自动打开浏览器
open: true,
// 端口号
port: 5555,
// 开启gzip压缩
compress: true,
},
};
Приведенный выше код является самым основным кодом этой статьи, и последующая оптимизация упаковки настраивается на основе этого файла.
Горячее обновление HMR
Модуль Heat Module Replace позволяет заменять, добавлять или удалять модули во время работы приложения без перезагрузки всей страницы.
преимущество:
- Сохранить состояние приложения, потерянное во время полной перезагрузки страницы.
- Обновляйте только изменения, чтобы сэкономить драгоценное время разработки.
- Когда CSS/JS изменяется в исходном коде, он будет немедленно обновлен в браузере, что почти эквивалентно изменению стиля непосредственно в инструментах разработки браузера.
картинка проблемы
Из приведенного выше рисунка видно, что когда мы меняем стиль, наш файл js выполняется повторно, что является проблемой для нашего проекта.Наше направление оптимизации — изменить этот файл, и перезагружается только этот файл.
код
Согласно приведенному выше вопросу, нам нужно только изменить код на devServer.
/*
* webpack.config.js
*/
...
module.exports = {
...
devServer: {
// 项目构建后的路径
contentBase: resolve(__dirname, "build"),
// 自动打开浏览器
open: true,
// 端口号
port: 5555,
// 开启gzip压缩
compress: true,
// 新增---> 开启热更新
// 模块热替换功能会在程序运行过程中,替换,添加或删除模块,而无需重新加载整个页面。
hot: true,
},
};
Изображение эффекта
режим отладки исходного кода devtool
Выберите формат исходной карты, чтобы улучшить процесс отладки. Различные значения могут существенно повлиять на скорость сборки и перестроения.
-
Отладка исходного кода для среды разработки
eval-source-map — медленно инициализирует исходную карту, но обеспечивает более быструю перестройку и создание реальных файлов. Счетчики строк отображаются правильно, потому что они отображаются в исходном коде. Он генерирует исходные карты наилучшего качества для среды разработки.
-
Отладка исходного кода для производственной среды
(нет) (опция devtool опущена) — не создавать исходные карты. Это хороший выбор.
Rule.oneOf соответствует правилам
правила сопоставления загрузчика.
/*
* webpack.config.js
*/
...
module.exports = {
...
// 模块
module: {
rules: [
// loader的配置
{
oneOf: [
// 以下的loader只会执行匹配的文件一次。
{
test: /\.css$/,
// 使用loader对文件进行处理
/**
* use数组中的执行顺序是 从右到左 从下到上 依次执行
* style-loader 创建style标签,将样式文件引入到header中
* css-loader 将css模块变成commonjs模块加载到js中, 文件内容是样式字符串
*/
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
// 将less文件编译成css文件
// 需要下载 less-loader和less
"less-loader",
],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
// webpack 5 内置了资源类型,已经废弃了之前的 url-loader 和 file-loader
type: "asset/resource",
},
{
test: /\.html$/,
// 处理html中的图片文件 引入img文件进而让url-loader处理
loader: "html-loader",
},
{
// 处理其他资源
exclude: /\.(html|js|css|less|png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource",
},
],
},
],
},
...
}
Таким образом, согласование загрузчика во время упаковки улучшит скорость.
файловый кеш
В продакшене мы можем кэшировать наши упакованные css и js и другие ресурсы в браузере, чтобы повысить скорость страницы, которую мы заходим во второй раз. Итак, нам нужно настроить webpack.config.js,Настройте кэширование для файлов js, файлов css и файлов изображений..
Сначала мы должны загрузить следующий загрузчик:
yarn add babel-loader @babel/core @babel/preset-env mini-css-extract-plugin --dev
Шаги оптимизации
- Извлеките файл css из связанного файла как отдельный файл.
- Используйте кеш babel для файлов js.
Извлечь css и кеш файловых ресурсов
/*
* webpack.config.js
*/
...
// 新增插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
...
// 模式
mode: "production",
output: {
filename: "built.[contenthash:10].js",
...
},
...
// 模块
module: {
rules: [
// loader的配置
{
oneOf: [
// 以下的loader只会执行匹配的文件一次。
{
test: /\.css$/,
// 将 style-loader 替换
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /\.less$/,
use: [
// 将 style-loader 替换
MiniCssExtractPlugin.loader,
"css-loader",
"less-loader",
],
},
...
// 新增js的loader
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
// 用来缓存 loader的执行结果。之后的webpack 构建,将会尝试读取缓存,
// 来避免在每次执行时,可能产生的、高性能消耗的 Babel
// 重新编译过程(recompilation process)。
cacheDirectory: true,
},
},
},
],
},
],
},
// 插件
plugins: [
...
//新增插件
new MiniCssExtractPlugin({
filename: "css/built.[contenthash:10].css",
}),
],
};
-
hash: уникальное значение хеш-функции генерируется каждый раз при сборке wepack.
- Проблема: потому что и js, и css используют хеш-значение.
- Переупаковка сделает недействительными все кеши. (Возможно, я изменил только один файл)
-
chunkhash: хеш-значение, сгенерированное в соответствии с чанком. Если пакет исходит из одного и того же фрагмента, значение хеш-функции будет таким же.
- Проблема: значение хеш-функции js и css остается одинаковым
- Поскольку css представлен в js, он принадлежит к тому же фрагменту
-
ContentHash: генерировать хеш-значение на основе содержимого файла.
- Хэш-значение разных файлов должно быть разным, чтобы лучше использовать кеш, когда код работает онлайн.
Добавьте jsloader и установите кеш
/*
* webpack.config.js
*/
...
module.exports = {
...
// 模块
module: {
rules: [
// loader的配置
{
oneOf: [
...
// 新增js的loader
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
// 用来缓存 loader的执行结果。之后的webpack 构建,将会尝试读取缓存,
// 来避免在每次执行时,可能产生的、高性能消耗的 Babel
// 重新编译过程(recompilation process)。
cacheDirectory: true,
},
},
},
],
},
],
},
...
};
Далее пишем тестовый код. Создайте новый файл server.js и создайте новый сервер для тестирования. Скачать экспресс-фреймворк.
yarn add express --dev
/*
* server.js
*/
const express = require("express");
const server = express();
// 缓存一个小时
server.use(express.static("build", { maxAge: 1000 * 3600 }));
server.listen(5555, () => {
console.log("服务器启动成功!", "http://localhost:5555/");
});
Проверить шаги кеша
- Упаковать веб-пакет в веб-пакет
- запустите узел сервера server.js
- http://localhost:5555/
Изображение эффекта
встряхивание дерева удаляет бесполезный код
Предпосылки для использования
- Должен использовать модульность ES6
- Открытая производственная среда
преимущество:При упаковке производственной среды мы можем игнорировать наш неиспользуемый код, удалять наш неиспользуемый код из файла упаковки и уменьшать размер файла упаковки.
дрожание дерева Пока мы соблюдаем два предыдущих условия, веб-пакет будет автоматически удалять недопустимый код при сборке.
Добавить тестовый файл
/*
* testTreeShaking.js
*/
export const test1 = () => {
console.log("test1");
};
export const test2 = () => {
console.log("test2");
};
Изменить файл
/*
* index.js
*/
...
import { test1 } from "./testTreeShaking";
test1();
// 未引入test2函数。打包时会忽略。
/*
* webpack.config.js
*/
...
module.exports = {
...
// 修改打包模式
mode: 'production',
...
};
Конфигурация в package.json
/*
* ackage.json
*/
"sideEffects": false
// 没有副作用(都可以进行tree shaking)
// 可能会把css / @babel/polyfill (副作用)文件干掉
"sideEffects": ["*.css", "*.less"]
Пакет webpack, просмотрите файл пакета, как показано ниже:
Как видите, функция test2 не упакована в файл пакета.
код сплит код сплит
Существует три типа разделения кода:
- Файлы с несколькими записями будут автоматически выполнять разделение кода
- Оптимизация.splitChunks управляет разделением кода.
- Оптимизация.splitChunks + import() для разделения кода
преимущество: Разделение кода может эффективно отклонять файлы js, которые слишком велики.
Файлы с несколькими записями будут автоматически выполнять разделение кода
/*
* webpack.config.js
*/
...
module.exports = {
...
entry: {
// 多入口:有一个入口,最终输出就有一个bundle
index: "./src/index.js",
test: "./src/testTreeShaking.js",
},
...
};
Эффект проверки пакета webpack, как показано ниже:
Оптимизация.splitChunks управляет разделением кода.
/*
* webpack.config.js
*/
...
module.exports = {
...
// 新增代码
optimization: {
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
splitChunks: {
//这表明将选择哪些 chunk 进行优化。当提供一个字符串,有效值为 all,async 和 initial。
//设置为 all 可能特别强大,因为这意味着 chunk 可以在异步和非异步 chunk 之间共享。
chunks: "all",
},
},
...
};
Эффект проверки пакета webpack, как показано ниже:
Оптимизация.splitChunks + import() для разделения кода
/*
* webpack.config.js
*/
...
module.exports = {
...
// 新增代码
optimization: {
/*
1. 可以将node_modules中代码单独打包一个chunk最终输出
2. 自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
splitChunks: {
//这表明将选择哪些 chunk 进行优化。当提供一个字符串,有效值为 all,async 和 initial。
//设置为 all 可能特别强大,因为这意味着 chunk 可以在异步和非异步 chunk 之间共享。
chunks: "all",
},
},
...
};
/*
* index.js
*/
/*
通过js代码,让某个文件被单独打包成一个chunk
import动态导入语法:能将某个文件单独打包
*/
import("./testTreeShaking").then(
(res) => {
console.log("res", res);
res.test1();
}
);
Эффект проверки пакета webpack, как показано ниже:
ленивая загрузка файлов предварительная загрузка
разница
- Перезагрузить с помощью файла
- Загружать первой, когда браузер бездействует
Изменить файл
/*
*index.html
*/
...
<button id="btn">加载testTreeShaking文件</button>
...
/*
*index.js
*/
console.log("加载index文件");
/*
*testTreeShaking.js
*/
export const test1 = () => {
console.log("test1");
};
export const test2 = () => {
console.log("test2");
};
console.log("加载index文件");
ленивая загрузка файла
/*
*index.js
*/
console.log("加载index文件");
document.getElementById("btn").onclick = function () {
// 懒加载:当文件需要使用时才加载
import("./testTreeShaking").then(({ test1 }) => {
test1();
});
};
Ленивая загрузка рендеринга
Предварительная загрузка
/*
*index.js
*/
console.log("加载index文件");
document.getElementById("btn").onclick = function () {
// 预加载 prefetch:会在使用之前,提前加载js文件
// 正常加载可以认为是并行加载(同一时间加载多个文件)
// 预加载 prefetch: webpackPrefetch 等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
import(/* webpackPrefetch: true */ "./testTreeShaking").then(({ test1 }) => {
test1();
});
};
Предварительная загрузка визуализаций
Прогрессивные веб-приложения PWA
PWA можно использовать для многих вещей. Наиболее важным из них является то, что приложение может продолжать функционировать в автономном режиме. Это достигается с помощью веб-технологии Service Workers.
Рендеринг PWA от Taobao
Добавьте плагин workbox-webpack-plugin, затем настройте файл webpack.config.js:
yarn add workbox-webpack-plugin --dev
Изменить webpack.config.js
/*
* webpack.config.js
*/
...
// 新增插件
const WorkboxWebpackPlugin = require("workbox-webpack-plugin");
module.exports = {
...
// 插件
plugins: [
...
//新增插件
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 帮助serviceworker快速启动
2. 删除旧的 serviceworker
生成一个 serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true,
}),
],
};
Зарегистрировать сервисного работника
/*
* index.js
*/
/*
sw代码必须运行在服务器上
--> nodejs
-->
npm server 启动服务器,将build目录下所有资源作为静态资源暴露出去
*/
// 注册serviceWorker
// 处理兼容性问题
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/service-worker.js")
.then(() => {
console.log("sw注册成功了~");
})
.catch(() => {
console.log("sw注册失败了~");
});
});
}
Далее мы скопируем предыдущий файл server.js и будем использовать его напрямую:
- упаковать первым
- узел server.js запускает сервер
- http://localhost:5555/
Проверьте изображение эффекта PWA
Мультипроцессная упаковка
yarn add thread-loader --dev
Измените файл webpack.config.js:
/*
* webpack.config
.js
*/
...
module.exports = {
...
// 模块
module: {
rules: [
// loader的配置
{
oneOf: [
...
// 新增js的loader
{
test: /\.js$/,
exclude: /node_modules/,
use: [
/*
新增代码
开启多进程打包。
进程启动大概为600ms,进程通信也有开销。
只有工作消耗时间比较长,才需要多进程打包
*/
{
loader: "thread-loader",
options: {
// 产生的 worker 的数量,默认是 (cpu 核心数 - 1),或者,
// 在 require('os').cpus() 是 undefined 时回退至 1
workers: 2, // 进程2个
},
},
...
],
},
],
},
],
},
...
};
Вы можете проверить эффект, запустив веб-пакет, потому что для запуска многопроцессорной упаковки требуется 600 мс, поэтому он больше подходит для проектов с большим объемом кода.
Многопроцессные визуализации упаковки без вскрытия
Включите визуализацию многопроцессорной упаковки
externals
Недопущение импорта некоторых пакетов (пакетов) запакованных в бандл, но (время выполнения) опять же зависит от получения этих расширений (внешних зависимостей) работающих извне.
Измените файл webpack.config.js и добавьте свойство externals.
/*
* webpack.config.js
*/
...
module.exports = {
...
externals: {
jquery: "jQuery",
},
};
Выберите ссылку CDN JQ и добавьте ее в index.html.
/*
* index.html
*/
<!DOCTYPE html>
<html lang="zn">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webpack打包优化</title>
<!-- 新增代码 -->
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
</head>
<body>
<h1>webpack 打包优化</h1>
<div class="color_1"></div>
<div class="color_2"></div>
<img src="./img/zp.jpg" />
</body>
</html>
/*
* index.js
*/
import $ from "jquery";
console.log("$", $);
webpack упакован для тестирования.
Изображение эффекта
Динамическая библиотека DLL
Реализовано разделение пакетов, а также значительно повышена скорость сборки. Термин «DLL» означает библиотеку динамической компоновки, первоначально представленную Microsoft.
Добавлен файл webpack.dll.js для отдельной настройки DllPlugin.
/*
* webpack.dll.js
*/
const { resolve } = require("path");
const webpack = require("webpack");
module.exports = {
entry: {
// 最终打包生成的[name] --> dllFile
// ['jquery',"lodash"] --> 要打包的库是jquery lodash
dllFile: ["jquery", "lodash"],
},
output: {
filename: "[name].js",
path: resolve(__dirname, "dll"),
library: "[name]_[hash]", // 打包的库里面向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个 manifest.json --> 提供和jquery lodash映射
new webpack.DllPlugin({
name: "[name]_[hash]", // 映射库的暴露的内容名称
path: resolve(__dirname, "dll/manifest.json"), // 输出文件路径
}),
],
mode: "production",
};
бегатьwebpack --config webpack.dll.jsВыполните этот файл, чтобы сгенерировать следующие файлы:
Измените файл webpack.config.js, чтобы настроить подключаемый модуль DllReferencePlugin AddAssetHtmlWebpackPlugin.
скачатьyarn add --dev add-asset-html-webpack-plugin
/*
* webpack.config.js
*/
...
// 新增代码
const webpack = require("webpack");
const AddAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin");
module.exports = {
...
plugins: [
...
// 新增代码
// 告诉webpack哪些库不参与打包,同时使用时的名称也得变~
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, "dll/manifest.json"),
}),
// 将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, "dll/dllFile.js"),
outputPath: "dll", // 如果设置,将用作文件的输出目录。
publicPath: "dll", // 如果设置,将用作脚本或链接标记的公共路径。
}),
],
};
Измените файл index.js для проверки:
/*
* index.js
*/
...
import $ from "jquery";
console.log("$--->jquery", $);
import _ from "lodash";
console.log("_---->lodash", _);
Запустите webpack для сборки. Сгенерируйте следующие файлы:
Проверьте беговой эффект
Это конец теории оптимизации упаковки webpack.На самом деле, есть еще много моментов по упаковке.Вы можете оставлять комментарии в области комментариев, и мы будем расти вместе! !
Учащиеся, желающие просмотреть исходный код, щелкните здесь, чтобы получить его.
Следующая статья Практика упаковки.