следующий24 примера для начала работы и освоения "Webpack4" (1)Следовать за:
- JS Tree Shaking
- CSS Tree Shaking
- Сводка по обработке изображения
- работа с файлами шрифтов
- Работа со сторонними библиотеками js
- Режим разработки и webpack-dev-сервер
- Режим разработки и режим производства・Настоящий бой
- Упаковка пользовательской библиотеки функций
9. Встряхивание дерева JS
Что такое встряска дерева?
Буквально означает встряхивание дерева, код, который не используется в проекте, будет выброшен при упаковке.Tree Shaking в JS опирается на модульную систему ES6 (например, импорт и экспорт).
Каталог проекта выглядит следующим образом:
Напишите тестовый код в файле util.js
// util.js
export function a() {
return 'this is function "a"'
}
export function b() {
return 'this is function "b"'
}
export function c() {
return 'this is function "c"'
}
Ссылка на функцию a() из util.js в app.js,Внедрить по требованию:
// app.js
import { a } from './vendor/util'
console.log(a())
После запуска пакета webpack в командной строке откройте пакет, сгенерированный после упаковки/dist/app.bundle.jsдокумент. Найди насa()
Строка, выводимая функцией, как показано на следующем рисунке:
Если вы замените то, что найти наthis is function "c"
илиthis is function "b"
, и не было найдено релевантных результатов поиска. Объясните, что JS Tree Shaking работает успешно.
1. Как быть со сторонними библиотеками JS?
Как реализовать Tree Shaking для часто используемых сторонних библиотек (таких как jQuery, lodash и т. д.)?
Давайте возьмем lodash.js в качестве примера.
Установите lodash.js:npm install lodash --save
Ссылка на функцию lodash.js в app.js:
// app.js
import { chunk } from 'lodash'
console.log(chunk([1, 2, 3], 2))
Упаковка командной строки. Как показано на рисунке ниже, размер пакета составляет 70 КБ. Очевидно, что упоминается только одна функция, и она не должна быть такой большой. Встряхивание дерева не выполняется.
Как упоминалось в начале, встряхивание дерева js использует модульную систему ES. в то время как lodash.js используетCommonJSвместоES6письма. Поэтому можно установить соответствующую модульную систему.
Установите ES-версию lodash.js:npm install lodash-es --save
Измените app.js:
// app.js
import { chunk } from 'lodash-es'
console.log(chunk([1, 2, 3], 2))
Упакуйте его еще раз, и упакованный результат составит всего 3,5 КБ (как показано на рисунке ниже). Судя по всему, встряхнуть дерево удалось.
При использовании сторонних библиотек в некоторых проектах, чувствительных к скорости загрузки, обратите внимание на то, соответствует ли написание библиотеки спецификации системы шаблонов ES, чтобы облегчить встряхивание дерева веб-пакета.
10. Встряхивание дерева CSS
CSS Tree Shaking не так прост для понимания, как JS Tree Shaking.Прежде всего, необходимо смоделировать реальную среду проекта, чтобы отразить конфигурацию и эффект CSS Tree Shaking.
Исходный код этой главы изменен на основе восьмого раздела, посвященного проектам CSS.
Сначала пишем файл стилей /src/css/base.css, в файле пишем 3 класса стилей. Но в коде мы будем использовать только два класса .box и .box--big. Код выглядит следующим образом:
/* base.css */
html {
background: red;
}
.box {
height: 200px;
width: 200px;
border-radius: 3px;
background: green;
}
.box--big {
height: 300px;
width: 300px;
border-radius: 5px;
background: red;
}
.box-small {
height: 100px;
width: 100px;
border-radius: 2px;
background: yellow;
}
В соответствии с обычными привычками использования добавление и выгрузка стилей посредством манипуляций с DOM является последовательным техническим средством. Итак, входной файл/src/app.js
создал<div>
тег и установите его класс на.box
// app.js
import base from './css/base.css'
// 给 app 标签再加一个 div 并且类名为 box
var app = document.getElementById('app')
var div = document.createElement('div')
div.className = 'box'
app.appendChild(div)
Наконец, чтобы приблизить окружение к реальному окружению, мыindex.html
Метка, которая также ссылается на определенный класс стиля box-big.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>CSS Tree Shaking</title>
</head>
<body>
<div id="app">
<div class="box-big"></div>
</div>
</body>
</html>
PurifyCSSпоможет намCSS Tree Shakingработать. Чтобы точно указать файл CSS, который будет использоваться для Tree Shaking, иglob-all(другая сторонняя библиотека).
glob-allРоль состоит в том, чтобы помочь PurifyCSSобработка пути, найдите файл пути для Tree Shaking.
Установить зависимости:
npm i glob-all purify-css purifycss-webpack --save-dev
Измените файл конфигурации:
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件
const PurifyCSS = require('purifycss-webpack')
const glob = require('glob-all')
module.exports = {
entry: {
app: './src/app.js'
},
output: {
publicPath: './', // js 引用的路径或者 CDN 地址
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
chunkFilename: '[name].js' // 代码拆分后的文件名
},
module: {
rules: [
{
test: /\.css$/, // 针对 .scss 或者 .css 后缀的文件设置 loader
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader'
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// 打包输出HTML
title: '自动生成 HTML',
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
filename: 'index.html', // 生成后的文件名
template: 'index.html', // 根据此模版生成 HTML 文件
chunks: ['app'] // entry中的 app 入口才会被打包
}),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
}),
// 清除无用 css
new PurifyCSS({
paths: glob.sync([
// 要做 CSS Tree Shaking 的路径文件
path.resolve(__dirname, './*.html'), // 请注意,我们同样需要对 html 文件进行 tree shaking
path.resolve(__dirname, './src/*.js')
])
})
]
}
Проверьте файл dist/app.css после упаковки
Стили, указанные в index.html и src/app.js, упакованы, но неиспользуемый класс стилей --box-small не упакован.
11. Резюме обработки изображений
Структура каталога:
Общие базовые операции с изображениями в webpack4:
- Обработка изображений и кодирование Base64
- Сжатие изображения
- Синтез спрайта FIG
(1) Подготовка
Как показано в каталоге кода проекта, в дополнение к общемуapp.js
В качестве входного файла мы будем использовать3картинка в/src/assets/imgs/
каталог и в файле стиляbase.css
процитировать эти изображения.
Оставь остальное наwebpack
Можно упаковать. Файлы стилей и записиapp.js
Коды файлов следующие:
/* base.css */
*,
body {
margin: 0;
padding: 0;
}
.box {
height: 400px;
width: 400px;
border: 5px solid #000;
color: #000;
}
.box div {
width: 100px;
height: 100px;
float: left;
}
.box .ani1 {
background: url('./../assets/imgs/1.jpg') no-repeat;
}
.box .ani2 {
background: url('./../assets/imgs/2.png') no-repeat;
}
.box .ani3 {
background: url('./../assets/imgs/3.png') no-repeat;
}
существуетapp.js
середина
import './css/base.css'
Установить зависимости:
npm install url-loader file-loader --save-dev
(2) Обработка изображений и кодирование base64
существуетwebpack.config.js
серединаmodule.rulesпараметры для настройкиloaderОпределите имя суффикса изображения и выполните указанную операцию обработки.
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
outputPath: 'images/', //输出到 images 文件夹
limit: 20000 //把小于 20kb 的文件转成 Base64 的格式
}
}
]
}
]
}
}
полный файл конфигурации
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件
module.exports = {
entry: {
app: './src/app.js'
},
output: {
publicPath: './', // js 引用的路径或者 CDN 地址
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
chunkFilename: '[name].js' // 代码拆分后的文件名
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader'
]
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
outputPath: 'images/', //输出到 images 文件夹
limit: 20000 //把小于 20kb 的文件转成 Base64 的格式
}
}
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// 打包输出HTML
title: '自动生成 HTML',
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
filename: 'index.html', // 生成后的文件名
template: 'index.html', // 根据此模版生成 HTML 文件
chunks: ['app'] // entry中的 app 入口才会被打包
}),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
})
]
}
Упакуйте проект, просмотрите результат упаковки и откройте его в браузере.index.html
документ
можно увидеть, кроме1.jpg, два других изображения были упакованы вbase64
формат, вapp.css
в файле
1.jpgЭтот документ превосходит то, что у нас есть вurl-loaderустановить в опцияхlimitзначение, поэтому он упакован отдельно
Это используетсяfile-loaderспособности, еслиurl-loaderустановить вlimitценность, нозависимости файлового загрузчика не установлены, что просходит? Давай сначала попробуемУдалить зависимости файлового загрузчика,npm uninstall file-loader
, а затем запустите команду пакета,npm run build
Если изображений слишком много, будет отправлено много http-запросов, что снизит производительность страницы.
url-loaderИмпортированное изображение будет закодировано и преобразовано в
base64
нить. Затем упакуйте эту строку символов в файл, и, наконец, вам нужно будет только импортировать этот файл, чтобы получить доступ к изображению, сохранив запрос изображения.
Однако, если изображение больше,Кодирование потребляет производительность. следовательноurl-loaderпредоставилlimitпараметр, не болееlimitфайлы bytes будут преобразованы вbase64
, больше, чемlimitиспользованиеfile-loaderОбрабатываются и упаковываются индивидуально.
url-loader зависит от file-loader, url-loader можно рассматривать как расширенную версию file-loader
(3) Сжатие изображения
Необходимо использовать сжатие изображенийimg-loaderплагины, в том числеДля разных типов изображений обратитесь к разным плагинам. Например, в нашем проекте используетсяpngфотографии, поэтому необходимо представитьimagemin-pngquant
и укажите степень сжатия. компрессияjpg/jpegкартинаimagemin-mozjpeg
плагин
вотbug, можно не торопясь, сначала прочтите этот раздел, а потом уже решайте! !
Установить зависимости
npm i img-loader imagemin imagemin-pngquant imagemin-mozjpeg --save-dev
Изменено в предыдущей конфигурации:
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
outputPath: 'images/', // 输出到 images 文件夹
limit: 20000 //把小于 20kb 的文件转成 Base64 的格式
}
}
]
}
изменить на:
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
limit: 1000, // size <= 1KB
outputPath: 'images/'
}
},
// img-loader for zip img
{
loader: 'img-loader',
options: {
plugins: [
require('imagemin-pngquant')({
quality: '80' // the quality of zip
}),
require('imagemin-mozjpeg')({
quality: '80'
})
]
}
}
]
}
Результат упаковки:
Причина в том, что на изображениях png изображения jpg могут быть сжаты, но перейдите кimagemin-pngquant githubВ интернете не нашел никого, кто бы поднимал подобную проблему, долго искал Baidu и google, но так и не нашел решения 😭, поэтому воспользовался другим плагином для сжатия картинок.image-webpack-loader
Сначала удалите предыдущие зависимости:
npm uni img-loader imagemin imagemin-pngquant imagemin-mozjpeg
Установить зависимости:
npm i image-webpack-loader --save-dev
Установка этой зависимости займет много времени. . . Вы можете сделать что-то еще в первую очередь. . .
Изменено в предыдущей конфигурации:
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
outputPath: 'images/', // 输出到 images 文件夹
limit: 20000 //把小于 20kb 的文件转成 Base64 的格式
}
}
]
}
изменить на:
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
limit: 1000, // size <= 1KB
outputPath: 'images/'
}
},
// img-loader for zip img
{
loader: 'image-webpack-loader',
options: {
// 压缩 jpg/jpeg 图片
mozjpeg: {
progressive: true,
quality: 65 // 压缩率
},
// 压缩 png 图片
pngquant: {
quality: '65-90',
speed: 4
}
}
}
]
}
здесьумышленноПучокurl-loaderизlimitЗначение атрибута установлено очень маленьким, чтобы оно не конвертировалосьpngкартинаbase64
, потому что мы хотим проверить сжатиеpngкартина
Результат упаковки:
Картинка сжата, и я смотрю на нее внимательно.Github для image-webpack-loader, на самом деле этоimage-webpack-loader
Плагин имеет несколько встроенных плагинов для сжатия изображений.
позвольте мне здесьочень смущенный, почему я устанавливаю напрямуюimagemin-pngquant
Нет, используйте вместо этогоimage-webpack-loader
Работает, так что проверюpackage-lock.json
файл, поискimage-webpack-loader
Я проверил, что последняя версия, которую я установил ранее,^7.0.0 !!!
Аси... Наконец нашел проблему,новая версияНекоторые проблемы не были решены должным образом, что привело к невозможности сжатия png-изображений.Определить проблему легко.В package.json поместитеimagemin-pngquant
Версия изменена на ^6.0.0, повторноnpm install
Затем выполните предыдущую операцию, вы можете сжать ее, соответствующий вариант выглядит следующим образом:
{
"devDependencies": {
"imagemin": "^6.1.0",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^6.0.0",
"img-loader": "^3.0.1"
}
}
При использованииimage-webpack-loader
, версия есть4.6.0
, импортированная версия зависимости также находится в белом поле
На этот раз я все еще используюimage-webpack-loader
, друзья могут выбрать, какой плагин использовать, простоimage-webpack-loader
Вводит зависимости от других форматов изображений, таких какsvg/webp/gifподождите, просто установитеimage-webpack-loader
достаточно, а другой - устанавливать по одному плагины, по сути принцип тот же
После этой отладки я понимаюНе последняя версия лучше, новая версия может обрабатываться неправильно или быть несовместимой с другими плагинами, что приводит к ошибке
Поэтому при установке сторонних зависимостей вам все равно нужнобудь осторожен,npm install по умолчанию устанавливает последнюю версию, если что-то пойдет не так,Откатиться на предыдущую стабильную версию, не только для
webpack
Плагины, то же самое для другого программного обеспечения или инструментов
Время написания этого подраздела:2019-3-9
, если при последующем изменении версии возникает ошибка, можно откатиться на предыдущую версию, не устанавливая последнюю версию.
(4) Создать карту спрайтов
Установить зависимости:
npm i postcss-loader postcss-sprites --save-dev
Полная конфигурация:
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件
/*********** sprites config ***************/
let spritesConfig = {
spritePath: './dist/images'
}
/******************************************/
module.exports = {
entry: {
app: './src/app.js'
},
output: {
publicPath: './', // js 引用的路径或者 CDN 地址
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
chunkFilename: '[name].js' // 代码拆分后的文件名
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader',
/*********** loader for sprites ***************/
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [require('postcss-sprites')(spritesConfig)]
}
}
/*********************************************/
]
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
limit: 1000, // size <= 1KB
outputPath: 'images/'
}
},
// img-loader for zip img
{
loader: 'image-webpack-loader',
options: {
// 压缩 jpg/jpeg 图片
mozjpeg: {
progressive: true,
quality: 65 // 压缩率
},
// 压缩 png 图片
pngquant: {
quality: '65-90',
speed: 4
}
}
}
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// 打包输出HTML
title: '自动生成 HTML',
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
filename: 'index.html', // 生成后的文件名
template: 'index.html', // 根据此模版生成 HTML 文件
chunks: ['app'] // entry中的 app 入口才会被打包
}),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
})
]
}
Проверьте результат после упаковки:
Изображение спрайта предназначено для уменьшения сетевых запросов, поэтому большинство обрабатываемых изображений спрайтов имеют различные типы.logoилиМаленькие картинки одинакового размера.
Для больших изображений не рекомендуется использовать спрайтовые изображения. Это сделает изображение больше
Кроме того, карта Sprite должна быть сопоставлена сcssКод для индивидуального использования. пройтиcssКод точно находит нужную картинку на карте Sprite
12. Обработка файла шрифта
Каталог проекта:
Зависимости, используемые в package.json, следующие:
{
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
"devDependencies": {
"clean-webpack-plugin": "^2.0.0",
"css-loader": "^2.1.0",
"file-loader": "^3.0.1",
"url-loader": "^1.1.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.5.0",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3"
}
}
Добавьте файлы шрифтов в app.js
import './assets/fonts/iconfont.css'
Настройте файл webpack.config.js для обработки шрифтов.
С помощью url-loader его можно распознать и обработатьэт, фуи т.д. конечный файл шрифта. При этом в зависимости от размера файла шрифта можно гибко настроить, выполнять ли кодировку base64.
Демонстрация ниже предназначена для выполнения кодирования base64, когда размер файла меньше 5000 байт.
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件
module.exports = {
entry: {
app: './src/app.js'
},
output: {
publicPath: './', // js 引用的路径或者 CDN 地址
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
chunkFilename: '[name].js' // 代码拆分后的文件名
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader'
]
},
{
test: /\.(eot|woff2?|ttf|svg)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg file
publicPath: 'fonts/',
outputPath: 'fonts/'
}
}
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// 打包输出HTML
title: '自动生成 HTML',
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
filename: 'index.html', // 生成后的文件名
template: 'index.html', // 根据此模版生成 HTML 文件
chunks: ['app'] // entry中的 app 入口才会被打包
}),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
})
]
}
Использовать шрифты в index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>处理字体文件</title>
</head>
<body>
<div id="app">
<div class="box">
<i class="iconfont icon-xiazai"></i>
<i class="iconfont icon-shoucang"></i>
<i class="iconfont icon-erweima"></i>
<i class="iconfont icon-xiangshang"></i>
<i class="iconfont icon-qiehuanzuhu"></i>
<i class="iconfont icon-sort"></i>
<i class="iconfont icon-yonghu"></i>
</div>
</div>
</body>
</html>
Проверьте файл index.html после упаковки, упаковка прошла успешно
13. Работа со сторонними js-библиотеками
Каталог проекта:
1. Как использовать сторонние JS-библиотеки и управлять ими?
После того, как проект станет больше, разработчики будут уделять больше внимания бизнес-логике и изо всех сил стараются использовать сторонние библиотеки JS для реализации других аспектов.
Поскольку js меняется так быстро, существует множество способов внедрения и управления сторонними библиотеками, и есть три наиболее часто используемых метода:
- CDN:
<script></script>
Импортировать ярлык - Управление пакетами npm:Наиболее часто используемый и рекомендуемый метод в настоящее время
- Локальные файлы js: по историческим причинам некоторые библиотеки не предоставляют версии ES6, их нужно скачать вручную, поместить в каталог проекта, а затем импортировать вручную.
Для третьего метода, если нет веб-пакета, вам нужно вручную импортировать импорт или требовать загрузки файлов; однако веб-пакет предоставляет настройку псевдонима, сwebpack.ProvidePluginЭтот плагин может пропустить ручной ввод и использовать его напрямую!
2. Напишите входной файл
Как показано на изображении каталога проекта, мы загрузилиjquery.min.js, размещенный в проекте. В то же время мытакже установил jquery через npm.
Чтобы максимально имитировать производственную среду, app.js используется для вызова $ jq, также мы используем jQuery для вызова jq.
Потому что в официальном проекте из-за необходимости слишком большого количества зависимостей библиотека, подключенная к объекту окна, подвержена конфликтам имен. На этом этапе библиотеку необходимо переименовать. Например: $ заменяется на jQuery.
Изменить в app.js
// app.js
$('div').addClass('new')
jQuery('div').addClass('old')
// 运行webpack后
// 浏览器打开 index.html, 查看 div 标签的 class
- написать файл конфигурации
webpack.ProvidePluginПараметры представляют собой пары ключ-значение, ключ — это имя переменной, используемой в нашем проекте, а значение — это библиотека, на которую указывает ключ.
webpack.ProvidePlugin сначала будет искать подходящую библиотеку из пакетов, установленных npm.
еслиwebpackнастроенresolve.aliasвариант (понимаемый как «псевдоним»), то webpack.ProvidePlugin найдет его по этой цепочке.
const path = require('path')
const webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
app: './src/app.js'
},
output: {
publicPath: './', // js 引用的路径或者 CDN 地址
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
chunkFilename: '[name].js' // 代码拆分后的文件名
},
resolve: {
alias: {
jQuery$: path.resolve(__dirname, 'src/vendor/jquery.min.js')
}
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// 打包输出HTML
title: '自动生成 HTML',
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
filename: 'index.html', // 生成后的文件名
template: 'index.html', // 根据此模版生成 HTML 文件
chunks: ['app'] // entry中的 app 入口才会被打包
}),
new webpack.ProvidePlugin({
$: 'jquery', // npm
jQuery: 'jQuery' // 本地Js文件
})
]
}
Измените файл index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>处理第三方 js 库</title>
</head>
<body>
<div></div>
</body>
</html>
Упакуйте и откройте index.html в Chrome. Как показано ниже,<div>
теги были добавленыoldа такжеnewДва урока стиля. Докажите, что и $, и jQuery, используемые в app.js, успешно указывают на библиотеку jquery.
14. Режим разработки и webpack-dev-сервер
1. Зачем нужен режим разработки?
В этих десяти стихах мы используем самыеПроизводственная среда, то есть выполнитьnpm run build
Команды для упаковки и сжатия различных файлов в проекте
Режим разработки должен указать режим как разработка. соответствует нашемуpackage.json
настроен вnpm run dev
, который также рассматривается во втором подразделе
В режиме разработки нам нужно отлаживать код. Соответствующая конфигурация:devtoolУстановить какsource-map. В режиме без разработки эту опцию необходимо отключить, чтобы уменьшить размер пакета. Подробнее см.:devtool
В режиме разработки вам также необходимогорячая перезагрузка,перенаправление маршрута,установить проксии другие функции, webpack4 предоставил опцию devServer для запуска локального сервера, что позволяет разработчикам использовать эти функции.
Структура каталога:
Установить зависимости
npm i webpack-dev-server --save-dev
Исправлятьpackage.json
{
"scripts": {
"dev": "webpack-dev-server --open",
"build": "webpack --mode production"
},
"devDependencies": {
"clean-webpack-plugin": "^2.0.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"jquery": "^3.3.1",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.2.1"
}
}
Поскольку у нас есть скрипт, настроенный в package.json, включить режим разработки несложно.npm run dev
Только что
Хотя консоль выводит информацию об упаковке (при условии, что мы настроили горячую перезагрузку), на диске нет создания/dist/Папки и пак-файлы. Содержимое файла пакета консоли хранится в памяти.
Измените файл index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>webpack-dev-server</title>
</head>
<body>
This is Index html
</body>
</html>
В соответствии с каталогом проекта просто инкапсулируйте три js-файла в /vendor/, чтобы облегчить вызов app.js:
// minus.js
module.exports = function(a, b) {
return a - b
}
// multi.js
define(function(require, factory) {
'use strict'
return function(a, b) {
return a * b
}
})
// sum.js
export default function(a, b) {
console.log('I am sum.js')
return a + b
}
Есть три способа импортировать файлы js в app.js:
import sum from './vendor/sum'
console.log('sum(1, 2) = ', sum(1, 2))
var minus = require('./vendor/minus')
console.log('minus(1, 2) = ', minus(1, 2))
require(['./vendor/multi'], function(multi) {
console.log('multi(1, 2) = ', multi(1, 2))
})
Теперь начните изменять webpack.config.js, полный файл конфигурации выглядит следующим образом:
const webpack = require('webpack')
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
app: './src/app.js'
},
output: {
publicPath: '/', // js 引用的路径或者 CDN 地址
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
chunkFilename: '[name].js' // 代码拆分后的文件名
},
mode: 'development', // 开发模式
devtool: 'source-map', // 开启调试
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: 8000, // 本地服务器端口号
hot: true, // 热重载
overlay: true, // 如果代码出错,会在浏览器页面弹出“浮动层”。类似于 vue-cli 等脚手架
proxy: {
// 跨域代理转发
'/comments': {
target: 'https://m.weibo.cn',
changeOrigin: true,
logLevel: 'debug',
headers: {
Cookie: ''
}
}
},
historyApiFallback: {
// HTML5 history模式
rewrites: [{ from: /.*/, to: '/index.html' }]
}
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
// 打包输出HTML
title: '自动生成 HTML',
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
filename: 'index.html', // 生成后的文件名
template: 'index.html', // 根据此模版生成 HTML 文件
chunks: ['app'] // entry中的 app 入口才会被打包
}),
new webpack.HotModuleReplacementPlugin(), // 热部署模块
new webpack.NamedModulesPlugin(),
new webpack.ProvidePlugin({
$: 'jquery', // npm
jQuery: 'jQuery' // 本地Js文件
})
]
}
Отдельный анализ приведенной выше конфигурации:
- Горячее обновление модуля
Требуется горячее обновление модуляHotModuleReplacementPluginа такжеNamedModulesPluginЭти два плагина,И порядок не может быть неправильным, и указать devServer.hot как true,
const webpack = require('webpack') // 引入 webpack
module.exports = {
plugins: [
new webpack.HotModuleReplacementPlugin(), // 热部署模块
new webpack.NamedModulesPlugin()
]
}
С помощью этих двух плагинов в проектеjsв кодеМожет обнаруживать и обрабатывать измененные файлы, вам не нужно писать кодОбновите страницу, он автоматически определяет измененный код и меняет его на странице
Обратите внимание, чтоjsКод, если перейти на изменение файла index.html, сохранить страницу не изменить, в противном случае перейти на изменение файла js, сохранить страницу обновится
Например, после запуска режима разработки мы модифицировалиvendor/sum.js
Этот файл на данный момент должен вывести некоторую информацию на консоль браузера. Так,app.jsможно записать так:
if (module.hot) {
// 检测是否有模块热更新
module.hot.accept('./vendor/sum.js', function() {
// 针对被更新的模块, 进行进一步操作
console.log('/vendor/sum.js is changed')
})
}
в любое времяsum.jsПосле изменения функция обратного вызова может выполняться автоматически.
Информация о выводе консоли браузера выглядит следующим образом:
Тем не менее, мы никогда не писали такой код в скаффолдинге vue, используемом в нашей повседневной разработке, и его также можно горячо обновлять, потому чтоvue-loaderЭтот метод встроен,css-loaderЕсть и в, так что мы можем увидеть обновление сразу после изменения кода js и css
- междоменный прокси
С ростом популярности раздельной разработки front-end и back-end междоменные запросы становятся все более и более распространенными. Для быстрой разработки вы можете использовать devServer.proxy для переадресации прокси-сервера, чтобы обойти междоменные ограничения браузера.
Нижний уровень модуля devServer должен использоватьhttp-proxy-middleware, есть много вещей, которые можно настроить
Согласно предыдущему файлу конфигурации, если вы хотите вызвать интерфейс Weibo:Нет. Weibo. Может /комментарии/ Хорошо…Просто запросите /comments/hotflow, добавьте следующий код в app.js:
$.get(
'/comments/hotflow',
{
id: '4263554020904293',
mid: '4263554020904293',
max_id_type: '0'
},
function(data) {
console.log(data)
}
)
Приведенный выше код предназначен для использования jQuery для отправки запроса на получение, если он находится в проекте vue, обычно используйте axios для отправки запроса.
После изменения app.js сохраните его, откройте предыдущую веб-страницу localhost:8000, и вы увидите запрос, отправленный сетью.
- HTML5–История
Когда в проекте используется API истории HTML5, любые ответы 404, возможно, потребуется заменить на index.html.
В SPA (одностраничном приложении) любой ответ напрямую заменяется index.html.
В официальном скаффолдинге vuejs vue-cli конфигурация в режиме разработки выглядит следующим образом:
historyApiFallback: {
// HTML5 history模式
rewrites: [{ from: /.*/, to: '/index.html' }]
}
Код в финальном app.js выглядит следующим образом:
import sum from './vendor/sum'
console.log('sum(1, 2) = ', sum(1, 2))
var minus = require('./vendor/minus')
console.log('minus(1, 2) = ', minus(1, 2))
require(['./vendor/multi'], function(multi) {
console.log('multi(1, 2) = ', multi(1, 2))
})
$.get(
'/comments/hotflow',
{
id: '4263554020904293',
mid: '4263554020904293',
max_id_type: '0'
},
function(data) {
console.log(data)
}
)
if (module.hot) {
// 检测是否有模块热更新
module.hot.accept('./vendor/sum.js', function() {
// 针对被更新的模块, 进行进一步操作
console.log('/vendor/sum.js is changed')
})
}
Откройте консоль и вы увидите, что код работает нормально, без ошибок. Кроме того, посколькуsource-map, чтобы вы могли найти позицию кода (в красном поле ниже):
Справочная статья:WebPack4 серия учебных пособий (XV): модель развития и WebPack-Dev-Server
15. Режим разработки и режим производства・Настоящий бой
Сначала создайте новую папку: demo15, выполнитеnpm init -y
инициализацияpackage.json
, сгенерированные файлы выглядят следующим образом:
{
"name": "example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Сначала очистим бесполезный код, оставив только код ключа:
{
"scripts": {}
}
Установить первымwebpackПолагаться на
npm i webpack webpack-cli webpack-dev-server --save-dev
Установитьbabel7, поскольку в настоящее время код в основном написан на ES6, его необходимо перевести
npm i @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime --save-dev
npm i @babel/polyfill @babel/runtime
Сейчасpackage.jsonЗависимости в:
{
"scripts": {},
"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/plugin-transform-runtime": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"babel-loader": "^8.0.5",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.2.1"
},
"dependencies": {
"@babel/polyfill": "^7.2.5",
"@babel/runtime": "^7.3.4"
}
}
новый.babelrcДля настройки плагина babel код выглядит следующим образом:
{
"presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-transform-runtime"]
}
новый.browserslistrcФайл настраивает версии браузеров, поддерживаемые проектом.
# 所支持的浏览器版本
> 1% # 全球使用情况统计选择的浏览器版本
last 2 version # 每个浏览器的最后两个版本
not ie <= 8 # 排除小于 ie8 及以下的浏览器
Прежде чем мы приступим к настройке файла webpack.config.js, нам нужно обратить внимание, потому что теперь у нас есть два режима,производство (производство) а такжеразработкамодель.
Установите автоматически сгенерированные html-зависимости
npm i html-webpack-plugin html-loader clean-webpack-plugin --save-dev
Установите зависимости обработки css/font-icon
npm i css-loader style-loader mini-css-extract-plugin optimize-css-assets-webpack-plugin --save-dev
Установите scss для обработки зависимостей
npm i node-sass sass-loader --save-dev
Префикс CSS для браузеров с разными ядрами
npm install postcss-loader autoprefixer --save-dev
Обработка изображений и шрифтов:
npm i url-loader file-loader image-webpack-loader --save-dev
сторонняя библиотека js
npm i jquery
Теперь package.json:
{
"scripts": {},
"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/plugin-transform-runtime": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"autoprefixer": "^9.4.10",
"babel-loader": "^8.0.5",
"clean-webpack-plugin": "^2.0.0",
"css-loader": "^2.1.1",
"file-loader": "^3.0.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^4.6.0",
"mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.11.0",
"optimize-css-assets-webpack-plugin": "^5.0.1",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.2.1"
},
"dependencies": {
"@babel/polyfill": "^7.2.5",
"@babel/runtime": "^7.3.4",
"jquery": "^3.3.1"
}
}
Раньше большинство из нас писали в производственном режиме, который часто называют упаковкой, но мы используем режим разработки для ежедневных проектов разработки.
Только после завершения проекта развертывание наnginxИспользуйте производственный режим только при загрузке, упакуйте код и поместите его вnginxсередина
Причина, по которой существует два режима, заключается в том, что в режиме разработки необходимоУскорение компиляции, возможность горячего обновления и установки междоменного адреса, включение отладки исходного кода (devtool: 'source-map')
В режиме сборки вам нужноСжимайте код js/css, разделяйте общие сегменты кода, разделяйте сторонние библиотеки js и т. д.
Таким образом, конфигурация здесь разделена на три файла для записи: один — производственная конфигурация, другой — конфигурация разработки, а последний — базовая конфигурация.
который:webpack.base.conf.js(базовая конфигурация),webpack.dev.conf.js(конфигурация разработки),webpack.prod.conf.js(производственная конфигурация)
новыйbuildпапку, создайте указанные выше три файла, структура проекта:
Здесь вам нужно использовать плагин,webpack-mergeИспользуется для объединения конфигураций, например, среда разработки объединяет конфигурацию разработки + базовую конфигурацию, а рабочая среда объединяет производственную конфигурацию + базовую конфигурацию.
npm i webpack-merge --save-dev
Сначала просто напишите пример кода webpack.base.conf.js.
const merge = require('webpack-merge')
const productionConfig = require('./webpack.prod.conf') // 引入生产环境配置文件
const developmentConfig = require('./webpack.dev.conf') // 引入开发环境配置文件
const baseConfig = {} // ... 省略
module.exports = env => {
let config = env === 'production' ? productionConfig : developmentConfig
return merge(baseConfig, config) // 合并 公共配置 和 环境配置
}
- Внедрить плагин webpack-merge для слияния конфигурации
- Внедрение рабочей среды и среды разработки
- Напишите базовую конфигурацию
- Экспорт объединенного файла конфигурации
Различайте разные среды в вашем коде:
module.exports = env => {
let config = env === 'production' ? productionConfig : developmentConfig
return merge(baseConfig, config) // 合并 公共配置 和 环境配置
}
Здесь env настраивается в package.json, модифицируйте скрипты, добавляйте команды «dev» и «build».
Обратите внимание, что есть--envполе, такое же, как env в webpack.base.conf.jsсвязь, сообщите ему, что такое текущая среда, а затем объединитесь с той средой,
{
"scripts": {
"dev": "webpack-dev-server --env development --open --config build/webpack.base.conf.js",
"build": "webpack --env production --config build/webpack.base.conf.js"
}
}
(1) Напишите базовую конфигурацию
const webpack = require('webpack')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件
const CleanWebpackPlugin = require('clean-webpack-plugin')
const path = require('path')
const productionConfig = require('./webpack.prod.conf.js') // 引入生产环境配置文件
const developmentConfig = require('./webpack.dev.conf.js') // 引入开发环境配置文件
/**
* 根据不同的环境,生成不同的配置
* @param {String} env "development" or "production"
*/
const generateConfig = env => {
// 将需要的 Loader 和 Plugin 单独声明
let scriptLoader = [
{
loader: 'babel-loader'
}
]
let cssLoader = [
'style-loader',
'css-loader',
'postcss-loader', // 使用 postcss 为 css 加上浏览器前缀
'sass-loader' // 使用 sass-loader 将 scss 转为 css
]
let cssExtractLoader = [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader',
'postcss-loader', // 使用 postcss 为 css 加上浏览器前缀
'sass-loader', // 使用 sass-loader 将 scss 转为 css
]
let fontLoader = [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg file
publicPath: 'fonts/',
outputPath: 'fonts/'
}
}
]
let imageLoader = [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
limit: 10000, // size <= 10KB
outputPath: 'images/'
}
},
// 图片压缩
{
loader: 'image-webpack-loader',
options: {
// 压缩 jpg/jpeg 图片
mozjpeg: {
progressive: true,
quality: 50 // 压缩率
},
// 压缩 png 图片
pngquant: {
quality: '65-90',
speed: 4
}
}
}
]
let styleLoader =
env === 'production'
? cssExtractLoader // 生产环境下压缩 css 代码
: cssLoader // 开发环境:页内样式嵌入
return {
entry: { app: './src/app.js' },
output: {
publicPath: env === 'development' ? '/' : './',
path: path.resolve(__dirname, '..', 'dist'),
filename: '[name]-[hash:5].bundle.js',
chunkFilename: '[name]-[hash:5].chunk.js'
},
module: {
rules: [
{ test: /\.js$/, exclude: /(node_modules)/, use: scriptLoader },
{ test: /\.(sa|sc|c)ss$/, use: styleLoader },
{ test: /\.(eot|woff2?|ttf|svg)$/, use: fontLoader },
{ test: /\.(png|jpg|jpeg|gif)$/, use: imageLoader }
]
},
plugins: [
// 开发环境和生产环境二者均需要的插件
new HtmlWebpackPlugin({
title: 'webpack4 实战',
filename: 'index.html',
template: path.resolve(__dirname, '..', 'index.html'),
// chunks: ['app'],
minify: {
collapseWhitespace: true
}
}),
new webpack.ProvidePlugin({ $: 'jquery' }),
new CleanWebpackPlugin()
]
}
}
module.exports = env => {
let config = env === 'production' ? productionConfig : developmentConfig
return merge(generateConfig(env), config) // 合并 公共配置 和 环境配置
}
Вышеуказанная конфигурация рекомендуется прочитать несколько более знакомых знакомых, почему вы хотите написать?
(2) Напишите файл конфигурации среды разработки
const webpack = require('webpack')
const path = require('path')
module.exports = {
mode: 'development',
devtool: 'source-map', // 调试源码
devServer: {
contentBase: path.join(__dirname, '../dist/'),
port: 8000,
hot: true,
overlay: true,
proxy: {
'/comments': {
target: 'https://m.weibo.cn',
changeOrigin: true,
logLevel: 'debug',
headers: {
Cookie: ''
}
}
},
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin()
]
}
Конфигурация разработки в основном предназначена для установки междоменного доступа, включения отладки исходного кода и горячего обновления.
(3) Запись файлов конфигурации производственной среды
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') // 压缩 css
module.exports = {
mode: 'production',
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
jquery: {
name: 'chunk-jquery', // 单独将 jquery 拆包
priority: 15,
test: /[\\/]node_modules[\\/]jquery[\\/]/
}
}
}
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
}),
// 压缩 css
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g, //一个正则表达式,指示应优化/最小化的资产的名称。提供的正则表达式针对配置中ExtractTextPlugin实例导出的文件的文件名运行,而不是源CSS文件的文件名。默认为/\.css$/g
cssProcessor: require('cssnano'), //用于优化\最小化 CSS 的 CSS处理器,默认为 cssnano
cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给 cssProcessor 的选项,默认为{}
canPrint: true //一个布尔值,指示插件是否可以将消息打印到控制台,默认为 true
})
]
}
**生产配置主要是拆分代码,压缩 css**
(4) Тестовый режим разработки
бегатьnpm run dev
И автоматически откройте браузер, изображения и шрифты отсутствуют, откройте консоль, чтобы увидеть междоменный успех, расположение исходного кода,Поскольку для devtool установлено значение «source-map», будет сгенерирован файл карты большего размера.
(5) Режим тестового производства
бегатьnpm run build
Откройте файл dist/index.html.
Это нормально для междоменных сбоев в производственном режиме, и если проект vue упакован, файл index.html нельзя напрямую открыть для просмотра эффекта.Он должен быть размещен на сервере.Как правило, упакованные файлы помещаются в nginx, настроить междоменные адреса в nginx
Существует также способ настройки среды разработки и производства веб-пакетов, который используется чаще:
Изменить webpack.base.conf.js
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
entry: {
app: './src/app.js'
},
output: {
path: path.resolve(__dirname, '..', 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
limit: 1000, // size <= 1KB
outputPath: 'images/'
}
},
// img-loader for zip img
{
loader: 'image-webpack-loader',
options: {
// 压缩 jpg/jpeg 图片
mozjpeg: {
progressive: true,
quality: 65 // 压缩率
},
// 压缩 png 图片
pngquant: {
quality: '65-90',
speed: 4
}
}
}
]
},
{
test: /\.(eot|ttf|svg)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]-[hash:5].min.[ext]',
limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg file
publicPath: 'fonts/',
outputPath: 'fonts/'
}
}
}
]
},
plugins: [
// 开发环境和生产环境二者均需要的插件
new HtmlWebpackPlugin({
title: 'webpack4 实战',
filename: 'index.html',
template: path.resolve(__dirname, '..', 'index.html'),
minify: {
collapseWhitespace: true
}
}),
new webpack.ProvidePlugin({ $: 'jquery' }),
new CleanWebpackPlugin()
],
performance: false
}
Изменить webpack.dev.conf.js
const webpack = require('webpack')
const merge = require('webpack-merge')
const commonConfig = require('./webpack.base.conf.js')
const path = require('path')
const devConfig = {
mode: 'development',
output: {
filename: '[name].js',
chunkFilename: '[name].js'
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2 // 在一个 css 中引入了另一个 css,也会执行之前两个 loader,即 postcss-loader 和 sass-loader
}
},
'postcss-loader', // 使用 postcss 为 css 加上浏览器前缀
'sass-loader' // 使用 sass-loader 将 scss 转为 css
]
}
]
},
devtool: 'cheap-module-eval-soure-map',
devServer: {
contentBase: path.join(__dirname, '../dist/'),
port: 8000,
hot: true,
overlay: true,
proxy: {
'/comments': {
target: 'https://m.weibo.cn',
changeOrigin: true,
logLevel: 'debug',
headers: {
Cookie: ''
}
}
},
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin()
]
}
module.exports = merge(commonConfig, devConfig)
Изменить webpack.prod.conf.js
const merge = require('webpack-merge')
const commonConfig = require('./webpack.base.conf.js')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') // 压缩 css
const prodConfig = {
mode: 'production',
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
},
devtool: 'cheap-module-source-map',
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
importLoaders: 2 // 在一个 css 中引入了另一个 css,也会执行之前两个 loader,即 postcss-loader 和 sass-loader
}
},
'postcss-loader', // 使用 postcss 为 css 加上浏览器前缀
'sass-loader' // 使用 sass-loader 将 scss 转为 css
]
}
]
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
jquery: {
name: 'jquery', // 单独将 jquery 拆包
priority: 15,
test: /[\\/]node_modules[\\/]jquery[\\/]/
},
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors'
}
}
}
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]-[contenthash].css',
chunkFilename: '[id]-[contenthash].css'
}),
// 压缩 css
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g, //一个正则表达式,指示应优化/最小化的资产的名称。提供的正则表达式针对配置中ExtractTextPlugin实例导出的文件的文件名运行,而不是源CSS文件的文件名。默认为/\.css$/g
cssProcessor: require('cssnano'), //用于优化\最小化 CSS 的 CSS处理器,默认为 cssnano
cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给 cssProcessor 的选项,默认为{}
canPrint: true //一个布尔值,指示插件是否可以将消息打印到控制台,默认为 true
})
]
}
module.exports = merge(commonConfig, prodConfig)
Измените команду скрипта package.json
{
"scripts": {
"dev": "webpack-dev-server --open --config ./build/webpack.dev.conf.js",
"build": "webpack --config ./build/webpack.prod.conf.js"
}
}
Я изменил конфигурацию на предыдущей основе и переупаковал ее.
Sixteen, упаковка пользовательской библиотеки функций
новыйindex.js,math.js,string.js
// index.js
import * as math from './math'
import * as string from './string'
export default { math, string }
// math.js
export function add(a, b) {
return a + b
}
export function minus(a, b) {
return a - b
}
export function multiply(a, b) {
return a * b
}
export function division(a, b) {
return a / b
}
// string.js
export function join(a, b) {
return a + ' ' + b
}
После того, как код написан, используйте webpack для упаковки, установите webpack, -D представляет собой аббревиатуру --save-dev
npm i webpack webpack-cli -D
Изменить package.json
{
"name": "library",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack"
},
"keywords": [],
"author": "xh",
"license": "MIT",
"devDependencies": {
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0"
}
}
"license": "MIT"
Указывает на полностью открытый протокол,name
Указывает имя вашей библиотеки компонентов
Создайте новый webpack.config.js и настройте
const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'library.js'
}
}
Запустите команду упаковки, чтобы сгенерировать файл library.js.
Этот файл можно использовать в проекте, но сейчас мы делаем библиотеку с открытым исходным кодом для использования другими, и другие могут использовать ее вот так.
// ES module
import library from 'library'
// CommonJS
const library = require('library')
// AMD
require(['library'], function() {})
Если мы хотим поддерживать использование этих трех форм, мы можем настроить их в веб-пакете, плюсlibraryTargetпараметр
const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'library.js',
libraryTarget: 'umd'
}
}
Конечно, если вы хотите, чтобы пользователи тоже импортировали в виде скриптовых тегов
<script src="library.js"></script>
Пользователи хотят иметь возможность использовать глобальные переменные библиотеки, например, что делать с library.math.
Вы можете настроить другой параметр, называемыйlibrary
const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'library.js',
library: 'root', // root 可以随便更换,不是固定值
libraryTarget: 'umd'
}
}
umd поддерживает первые три синтаксиса, но не поддерживает использование глобальных переменных.Если настроена библиотека, код будет смонтирован вrootВ этой глобальной переменной,scriptДавайте импортируем библиотеку, давайте упакуем ее сейчас, а затем протестируем тег script, чтобы импортировать библиотеку, которую мы написали.
Создайте новый файл index.html в каталоге dist и откройте страницу.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>自定义库</title>
<script src="./library.js"></script>
</head>
<body></body>
</html>
Введите root в консоли, нажмите Enter, и вы увидите функцию, которую мы инкапсулировали ранее.
libraryTarget: 'umd'
еслиumdизменить наthis
Снова зайдите в package и введите в консолиthis.rootтакже увидеть эффект
libraryTarget
также можно заполнитьwindow, если вы также можете использовать его в среде узлаglobal
Но обычно мы используем umd
Есть еще одна ситуация, на которую стоит обратить внимание: я думаю, что string.js, который мы сейчас пишем, не очень хорош, а lodash лучше, и я хочу представить эту стороннюю библиотеку для замены некоторых функций, которые я написал.
npm install lodash
// string.js
import _ from 'lodash'
export function join(a, b) {
return _.join([a, b], ' ')
}
Переупакован в 70 КБ, потому что мы также упаковали lodash в
Если другие хотят использовать нашу библиотеку, им нужно этоimport library from 'library'
, возможно, другие также будут использовать библиотеку lodash, и результат будет таким:
import _ from 'lodash'
import library from 'library'
в коде конечного пользователядвакод lodash, в этом случае нам нужно снова изменить конфигурацию нашего веб-пакета
const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
externals: ['lodash'],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'library.js',
library: 'root',
libraryTarget: 'umd'
}
}
externalsВ процессе упаковки, если вы столкнетесь с библиотекой lodash, она не будет упакована и может быть записана какмножествоФорма также может бытьнитьПосле замены упакуйте еще раз.
Можно обнаружить, что лодаш, используемый в нашей библиотеке, не упакован, а объем всего 1кб
В это время другие снова пользуются нашей библиотекой,Сбой, если lodash не введен, другие должны ввести lodash перед использованием библиотеки
Если вместо этогоexternals: 'lodash'
, то при использованииimport lodash from lodash
, Вместо того, чтобы использовать подчеркивание _ вместо lodash,import _ from lodash
Если вы хотите, чтобы другие использовали вашу библиотеку, вы фактически используете свои упакованные файлы, вам нужно сначала изменить main: index.js на main: ./dist/library.js в package.json и передатьnpm выпускатьПрежде вы должны убедиться, что имя вашей библиотеки не конфликтует с именами других в сети, и изменить уникальное имя, чтобы обеспечить успешную публикацию, например,library-xh-2019
, если вам интересно, вы можете изучить, как опубликовать его через npm
{
"name": "library-xh-2019",
"version": "1.0.0",
"description": "",
"main": "./dist/library.js",
"scripts": {
"build": "webpack"
},
"keywords": [],
"author": "xh",
"license": "MIT",
"devDependencies": {
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0"
},
"dependencies": {
"lodash": "^4.17.11"
}
}