В: Для кого эта статья?
О: Это подходит для людей, которые не знакомы с Webpack или имеют неполное представление.
В: Как устроено содержание этой статьи?
A: Сначала представьте предысторию, познакомьте с концепцией Webpack из предыстории, а затем познакомьтесь с основой, ядром и некоторыми распространенными случаями конфигурации и методами оптимизации Webpack.В Webpack действительно много плагинов и загрузчиков, и только небольшая часть из них покрыты всего 2w слов.
Вопрос: Откуда эта статья?
Ответ: Знание этой статьи происходит из платного видео (ссылка в конце статьи), статья написана мной самостоятельно, авторизована лектором и впервые опубликована в Наггетс
Предыдущий:Начните сегодня, изучите Webpack и уменьшите свою зависимость от скаффолдинга (часть 1)
Если вы считаете, что текст хороший, пожалуйста, дайте мне звездочку, оригинальный адрес блога:исходный адрес
Конфигурация ПВА
Полное имя PWAProgressive Web Application
(Прогрессивная платформа приложений), она позволяет нам активно кэшировать файлы, чтобы пользователи по-прежнему могли использовать наши кэшированные файлы для открытия веб-страниц после отключения от сети, не вызывая зависания страницы. Внедрение этой технологии требует установкиworkbox-webpack-plugin
плагин.
Если в вашем браузере Google Chrome не включена поддержка PWA, включите ее и выполните следующий тест.
Установить плагин
$ npm install workbox-webpack-plugin -D
Конфигурация файла webpack.config.js
// PWA只有在线上环境才有效,所以需要在webpack.prod.js文件中进行配置
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const prodConfig = {
// 其它配置
plugins: [
new MiniCssExtractPlugin({}),
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
})
]
}
module.exports = merge(commonConfig, prodConfig);
После того, как приведенная выше конфигурация завершена, давайте использоватьnpm run build
Пакет, чтобы увидеть, какие файлы генерируются,dist
Результат упаковки каталога выглядит следующим образом:
|-- dist
| |-- index.html
| |-- main.f28cbac9bec3756acdbe.js
| |-- main.f28cbac9bec3756acdbe.js.map
| |-- precache-manifest.ea54096f38009609a46058419fc7009b.js
| |-- service-worker.js
Мы можем выделить часть блока кода, болееprecache-manifest.xxxxx.js
документы иservice-worker.js
, именно эти два файла позволяют реализовать PWA.
Переписать index.js
Нужно определить, поддерживает ли браузер PWA, когда будет поддерживаться, будем регистрироваться и регистрироваться..js
Файл упакован для насservice-worker.js
документ.
console.log('hello,world');
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js').then((register) => {
console.log('注册成功');
}).catch(error => {
console.log('注册失败');
})
}
Фактический эффект PWA
существуетnpm run dev
После этого используемwebpack-dev-server
Запускается небольшой сервер, затем мы останавливаем сервер, обновляем страницу, и фактический результат PWA показан на следующем рисунке.
Переадресация запросов WebpackDevServer
В этом разделе мы изучим следующие навыки:
- Как настроить прокси интерфейса
- Как использовать перезапись пути интерфейса
- Знакомство с другими распространенными конфигурациями
Предположим, у нас сейчас есть такое требование: у меня есть URL-адрес (http://www.dell-lee.com/react/api/header.json
), я надеюсь, что когда я запрашиваю, запрошенный адрес/react/api/header.json
, может быть что-то, что может автоматически помочь мне переслать запрос наhttp://www.dell-lee.com
доменное имя, как решить эту проблему? Вы можете использовать Webpackwebpack-dev-server
Этот плагин для решения, который нужно настроитьproxy
Атрибуты.
Как настроить прокси интерфейса
Поскольку мы собираемся делать запросы, установитеaxios
Правильнее отправить запрос, используйте следующую команду для установкиaxios
:
$ npm install axios --save-dev
Поскольку наш прокси-сервер запросов можно использовать только в среде разработки, для рабочей онлайн-среды требуются другие конфигурации прокси-сервера, поэтому нам нужноwebpack.dev.js
настройка прокси в
const devConfig = {
// 其它配置
devServer: {
contentBase: './dist',
open: false,
port: 3000,
hot: true,
hotOnly: true,
proxy: {
'/react/api': {
target: 'http://www.dell-lee.com'
}
}
}
}
После того, как вышеуказанная конфигурация завершена, мыindex.js
импортируется в файлaxios
модуль, а затем перенаправить запрос.
import axios from 'axios';
axios.get('/react/api/header.json').then((res) => {
let {data,status} = res;
console.log(data);
})
использоватьnpm run dev
После этого мы можем увидеть в браузере, что мы успешно запросили наши данные.
Как использовать перезапись пути интерфейса
Теперь все же предположим, что есть такой сценарий:http://www.dell-lee.com/react/api/header.json
Этот бэкэнд-интерфейс еще не разработан, но бэкэнд говорит нам, что мы можем использовать его в первую очередь.http://www.dell-lee.com/react/api/demo.json
Это тестовый интерфейс, мы изменим его обратно после того, как интерфейс будет разработан. Лучший способ решить эту проблему — адрес в коде изменить нельзя, мы толькоproxy
Его можно обработать в прокси, используяpathRewrite
свойства для настройки.
const devConfig = {
// 其它配置
devServer: {
contentBase: './dist',
open: false,
port: 3000,
hot: true,
hotOnly: true,
proxy: {
'/react/api': {
target: 'http://www.dell-lee.com',
pathRewrite: {
'header.json': 'demo.json'
}
}
}
}
}
Точно так же мы можем видеть в браузере после упаковки, что данные нашего тестового интерфейса были успешно получены.
Последствия других распространенных конфигураций
Переслать на https:В общем, недопустимо бегать вhttps
включено, если вы хотите переслатьhttps
, вы можете использовать следующую конфигурацию
module.exports = {
//其它配置
devServer: {
proxy: {
'/react/api': {
target: 'https://www.dell-lee.com',
secure: false
}
}
}
}
Перекрестный домен:Иногда в процессе запроса, благодаря воздействию гомологичных стратегий, существует перекрестная проблема, нам нужно обрабатывать эту ситуацию, которая может быть настроена следующим образом.
module.exports = {
//其它配置
devServer: {
proxy: {
'/react/api': {
target: 'https://www.dell-lee.com',
changeOrigin: true,
}
}
}
}
Проксировать несколько путей к одной и той же цели:прокси несколько путей к одному и тому жеtarget
, который можно настроить следующим образом
module.exports = {
//其它配置
devServer: {
proxy: [{
context: ['/vue/api', '/react/api'],
target: 'http://www.dell-lee.com'
}]
}
}
Многостраничная упаковка
Сейчас популярные front-end фреймворки реализуют одностраничные ссылки (SPA), но иногда нам приходится быть совместимыми с некоторыми старыми проектами, они многостраничные, так как же настроить многостраничную упаковку?
Теперь давайте подумаем о проблеме: многостраничное использование, т.е.Несколько файлов записей + несколько соответствующих файлов html, то мы можем настроитьНесколько записей + несколько конфигурацийhtml-webpack-plugin
продолжать.
Сценарий: Предположим, теперь у нас есть три таких страницы:index.html
, list.html
, detail.html
, нам нужно настроить три файла входа и создать три новых.js
документ.
существуетwebpack.common.js
настроить несколькоentry
и использоватьhtml-webpack-plugin
для создания соответствующего множественного.html
страница.Описание параметра HtmlWebpackPlugin:
-
template
: указывает, какую HTML-страницу использовать в качестве шаблона. -
filename
: Представляет имя файла сгенерированной страницы. -
chunks
: Представляет, на какие пакеты нужно ссылаться..js
документ
module.exports = {
// 其它配置
entry: {
index: './src/index.js',
list: './src/list.js',
detail: './src/detail.js',
},
plugins: [
new htmlWebpackPlugin({
template: 'src/index.html',
filename: 'index.html',
chunks: ['index']
}),
new htmlWebpackPlugin({
template: 'src/index.html',
filename: 'list.html',
chunks: ['list']
}),
new htmlWebpackPlugin({
template: 'src/index.html',
filename: 'detail.html',
chunks: ['detail']
}),
new cleanWebpackPlugin()
]
}
существуетsrc
Создайте три новых каталога.js
Файлы называются:index.js
,list.js
а такжеdetail.js
, их коды следующие:
// index.js代码
document.getElementById('root').innerHTML = 'this is index page!'
// list.js代码
document.getElementById('root').innerHTML = 'this is list page!'
// detail.js代码
document.getElementById('root').innerHTML = 'this is detail page!'
бегатьnpm run build
Упаковать:
$ npm run build
упакованныйdist
содержание:
|-- dist
| |-- detail.dae2986ea47c6eceecd6.js
| |-- detail.dae2986ea47c6eceecd6.js.map
| |-- detail.html
| |-- index.ca8e3d1b5e23e645f832.js
| |-- index.ca8e3d1b5e23e645f832.js.map
| |-- index.html
| |-- list.5f40def0946028db30ed.js
| |-- list.5f40def0946028db30ed.js.map
| |-- list.html
случайный выборlist.html
Запустив его в браузере, результат выглядит следующим образом:
Мысль: Страниц сейчас всего три, то есть надо настроить три записи + три соответствующихhtml
, если у нас десять подъездов, мы тоже делаем это дублирование труда? Есть ли что-нибудь, что может помочь нам сделать это автоматически? Конечно, да!
Сначала мы определяемmakeHtmlPlugins
метод, который принимает параметр конфигурации Webpackconfigs
, который возвращаетplugins
множество
const makeHtmlPlugins = function (configs) {
const htmlPlugins = []
Object.keys(configs.entry).forEach(key => {
htmlPlugins.push(
new htmlWebpackPlugin({
template: 'src/index.html',
filename: `${key}.html`,
chunks: [key]
})
)
})
return htmlPlugins
}
позвонивmakeHtmlPlugins
метод, который возвращаетhtml
изplugins
массив, объедините его с исходнымplugin
Объединить, а затем скопировать вconfigs
configs.plugins = configs.plugins.concat(makeHtmlPlugins(configs));
module.exports = configs;
После того, как вышеуказанная конфигурация завершена, результат упаковки остается прежним, пожалуйста, проверьте его самостоятельно, следующееwebpack.commom.js
Полный код:
const path = require('path');
const webpack = require('webpack');
const htmlWebpackPlugin = require('html-webpack-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
const miniCssExtractPlugin = require('mini-css-extract-plugin');
const optimizaCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const configs = {
entry: {
index: './src/index.js',
list: './src/list.js',
detail: './src/detail.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: miniCssExtractPlugin.loader,
options: {
hmr: true,
reloadAll: true
}
},
'css-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: [
{
loader: "babel-loader"
},
{
loader: "imports-loader?this=>window"
}
]
}
]
},
plugins: [
new cleanWebpackPlugin(),
new miniCssExtractPlugin({
filename: '[name].css'
}),
new webpack.ProvidePlugin({
'$': 'jquery',
'_': 'lodash'
})
],
optimization: {
splitChunks: {
chunks: 'all'
},
minimizer: [
new optimizaCssAssetsWebpackPlugin()
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname,'../dist')
}
}
const makeHtmlPlugins = function (configs) {
const htmlPlugins = []
Object.keys(configs.entry).forEach(key => {
htmlPlugins.push(
new htmlWebpackPlugin({
template: 'src/index.html',
filename: `${key}.html`,
chunks: [key]
})
)
})
return htmlPlugins
}
configs.plugins = configs.plugins.concat(makeHtmlPlugins(configs))
module.exports = configs
Как упаковать файл библиотеки (Library)
Почти все приведенные выше конфигурации Webpack предназначены для бизнес-кода.Если мы хотим упаковать и выпустить библиотеку для использования другими, как нам ее настроить? В следующих нескольких разделах мы поговорим о том, как упаковать файл библиотеки и сделать этот файл библиотеки пригодным для использования в различных сценариях.
Создать новый проект
шаг:
- Создать проект библиотеки
- использовать
npm init -y
настроитьpackage.json
- новый
src
каталог, создатьmath.js
документ,string.js
документ,index.js
документ - Создал в корневом каталоге
webpack.config.js
документ - Установить
webpack
,webpack-cli
:::
После выполнения вышеуказанных шагов ваш каталог, вероятно, будет выглядеть так:
|-- src
| |-- index.js
| |-- math.js
| |-- string.js
|-- webpack.config.js
|-- package.json
Инициализировать package.json
// 初始化后,改写package.json
{
"name": "library",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "MIT"
}
Создайте каталог src и добавьте файлы
существуетsrc
новый каталог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;
}
существуетsrc
новый каталогstring.js
, который имеетjoin
Методы, как показано ниже:
export function join(a, b) {
return a + '' + b;
}
существуетsrc
новый каталогindex.js
файл, который ссылаетсяmath.js
а такжеstring.js
и экспортировать следующим образом:
import * as math from './math';
import * as string from './string';
export default { math, string };
добавить webpack.config.js
Поскольку мы собираемся упаковать файл библиотеки, поэтомуmode
Настроен только для производства (production
) может быть использован.
После добавления вышеуказанных файлов давайте настроимwebpack.config.js
Файл, его код очень прост, выглядит следующим образом:
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'library.js',
path: path.resolve(__dirname, 'dist')
}
}
Установить вебпак
Поскольку это связано с упаковкой Webpack, нам нужно использоватьnpm instll
Установить:
$ npm install webpack webpack-cli -D
Сделать первую упаковку
использоватьnpm run build
Для первой упаковки вdist
Каталог называетсяlibrary.js
файл, если мы хотим проверить этот файл, нам нужноdist
новый каталогindex.html
$ npm run build
$ cd dist
$ touch index.html
существуетindex.html
введен вlibrary.js
документ:
<script src="./library.js"></script>
На данный момент мы в основном завершили построение каталога проекта Теперь давайте рассмотрим ситуации, в которых мы можем использовать наши упакованные файлы:
- использовать
ES Module
Импорт синтаксиса, например.import library from 'library'
- использовать
CommonJS
Импорт синтаксиса, например.const library = require('library')
- использовать
AMD
,CMD
Импорт синтаксиса, например.require(['library'], function() {// todo})
- использовать
script
Введение этикетки, например.<script src="library.js"></script>
Для приведенных выше сценариев использования мы можем настроить свойства library и libraryTarget в выходных данных (примечание: здесь library и libraryTarget не имеют ничего общего с именем нашей библиотеки library.js, первое является неотъемлемым элементом конфигурации Webpack, второе — просто наше произвольное имя берем)
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
library: 'library',
libraryTarget: 'umd'
}
}
Описание свойства конфигурации:
-
library
: это свойство относится к глобальной переменной нашей библиотеки, подобноjquery
середина$
символ -
libraryTarget
: этот атрибут относится к схеме импорта модулей, которую должна поддерживать наша библиотека.umd
Представительская поддержкаES Module
,CommomJS
,AMD
так же какCMD
После завершения настройки используемnpm run build
упаковать и запустить в браузереindex.html
,существуетconsole
консольный выводlibrary
Это глобальная переменная, результат которой показан на следующем рисунке:
Библиотека, которую мы написали выше, очень проста, в процессе разработки библиотеки нам часто приходится использовать некоторыесторонняя библиотека, если мы не будем делать другую настройку, сторонняя библиотека будет упакована прямо в файл нашей библиотеки.
Если пользователь также введет эту стороннюю библиотеку при использовании нашего файла библиотеки, это вызовет проблему повторного обращения, то как решить эту проблему? допустимыйwebpack.config.js
конфигурация в файлеexternals
Атрибуты.
существуетstring.js
документjoin
метод, мы используем стороннюю библиотекуlodash
середина_join()
метод объединения строк.
import _ from 'lodash';
export function join(a, b) {
return _.join([a, b], ' ');
}
После модификацииstring.js
файл, использоватьnpm run build
упаковать, обнаружитьlodash
Он напрямую упакован в наш файл библиотеки, в результате чего файл библиотеки активно раздувается до 70,8 КБ.
$ npm run build
Built at: 2019-04-05 00:47:25
Asset Size Chunks Chunk Names
library.js 70.8 KiB 0 [emitted] main
Для решения вышеуказанных проблем мы можемwebpack.config.js
Средняя конфигурацияexternals
недвижимость, большеexternals
использование, пожалуйста, нажмитеexternals
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
externals: ['lodash'],
output: {
filename: 'library.js',
path: path.resolve(__dirname, 'dist'),
library: 'library',
libraryTarget: 'umd'
}
}
Настроеноexternals
После этого мы снова упаковываем его, и результат упаковки выглядит следующим образом: мы видим, что файл нашей библиотеки вернулся к исходному размеру, что доказывает, что наша конфигурация работает.
$ npm run build
Built at: 2019-04-05 00:51:22
Asset Size Chunks Chunk Names
library.js 1.63 KiB 0 [emitted] main
Как публиковать и использовать файлы нашей библиотеки
После упаковки, как мы публикуем файлы нашей библиотеки, следующееШаги для публикации:
- регистр
npm
учетная запись - Исправлять
package.json
Запись файла изменена на:"main": "./dist/library.js"
- бегать
npm adduser
Добавить имя учетной записи - бегать
npm publish
команда для публикации - бегать
npm install xxx
установить
Чтобы поддерживать чистоту репозитория npm, мы фактически не запускали команду npm publish, потому что наша библиотека бессмысленна, а ее публикация — это мусорный код, поэтому, пожалуйста, попробуйте опубликовать ее самостоятельно. Кроме того, имя вашего собственного пакета не может совпадать с именем существующего пакета в репозитории npm, поэтому вам нужно присвоить атрибуту name специальное имя в package.json, например "name": "why- библиотека-2019"
Конфигурация TypeScript
вместе сTypeScript
непрерывное развитие, считаю, что будущее использованиеTypeScript
писать код JS станет мейнстримом, поэтому как настроить поддержку в WebpackTypeScript
Шерстяная ткань? может быть установленts-loader
а такжеtypescript
Для решения этой проблемы.
Создайте новый проект webpack-typescript
Создайте новый проект и назовите егоwebpack-typescript
, и действуйте следующим образом:
- использовать
npm init -y
инициализацияpackage.json
файл и добавитьbuild
Команда упаковки Webpack - новый
webpack.config.js
файл и выполните простую настройку, напримерentry
,output
Ждать - новый
src
каталог и вsrc
новый каталогindex.ts
документ - новый
tsconfig.json
файл и сделать некоторые настройки - Установить
webpack
а такжеwebpack-cli
- Установить
ts-loader
а такжеtypescript
После выполнения вышеуказанных действий каталог проекта будет выглядеть следующим образом:
|-- src
| |-- index.ts
|-- tsconfig.json
|-- webpack.config.js
|-- package.json
существуетpackage.json
Добавьте команду пакета в команду:
"scripts": {
"build": "webpack"
},
Далее нам нужноwebpack.config.js
Сделайте некоторую настройку:
const path = require('path');
module.exports = {
mode: 'production',
module: {
rules: [
{
test: /\.(ts|tsx)?$/,
use: {
loader: 'ts-loader'
}
}
]
},
entry: {
main: './src/index.ts'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
существуетtsconfig.json
осуществляется внутриtypescript
соответствующая конфигурация, описание элементов конфигурации выглядит следующим образом
-
module
: означает, что мы используемES6
модуль -
target
: означает, что мы конвертируем вES5
код -
allowJs
: позвольте нам.ts
через файлimport
Грамматика знакомит с другими.js
документ
{
"compilerOptions": {
"module": "ES6",
"target": "ES5",
"allowJs": true
}
}
существуетsrc/index.ts
запись в документеTypeScript
код, как показано ниже
class Greeter {
greeting: string
constructor(message: string) {
this.greeting = message;
}
greet() {
return 'hello, ' + this.greeting;
}
}
let greeter = new Greeter('why');
console.log(greeter.greet());
пакетный тест
- бегать
npm run build
упаковать - в создании
dist
каталог, создайте новыйindex.html
, и представьте упакованныйmain.js
документ - запустить в браузере
index.html
Использовать файлы определения типов из других модулей
Если мы хотим использовать библиотеку lodash, мы должны установить соответствующий файл определения типа в формате @types/xxx.
Установитьlodash
соответствующийtypescript
Тип файла:
$ npm install lodash @types/lodash -D
После установки мыindex.ts
цитируется вlodash
, и используйте метод внутри:
import * as _ from 'lodash'
class Greeter {
greeting: string
constructor(message: string) {
this.greeting = message;
}
greet() {
return _.join(['hello', this.greeting], '**');
}
}
let greeter = new Greeter('why');
console.log(greeter.greet());
пакетный тест
использоватьnpm run build
, Запуск в браузереindex.html
, результат следующий:
Оптимизация производительности веб-пакета
Анализ упаковки
Перед выполнением оптимизации производительности Webpack, если мы знаем, насколько велик каждый из наших связанных файлов и каково время упаковки, нам очень полезно выполнить оптимизацию производительности.Здесь мы используемwebpack-bundle-analyzer
чтобы помочь нам решить эту проблему.
Сначала вам нужно установить плагин с помощью следующей команды:
$ npm install webpack-bundle-analyzer --save-dev
После установки нам нужноwebpack.prod.js
Внесите небольшое изменение в файл:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const prodConfig = {
// 其它配置项
mode: 'production',
plugins: [
new BundleAnalyzerPlugin()
]
}
После настройки запускаемnpm run build
команда для просмотра результатов анализа упаковки. Следующие результаты упаковки приведены только для справки:
Сузить поиск файлов
Сначала нам нужно понять параметр конфигурации Webpack (Resolve
) роль: она сообщает Webpack, как искать файлы, а также имеет несколько свойств, которые нам нужно понять:
-
extensions
: он сообщает Webpack, как искать модули, когда мы импортируем модуль без написания суффикса модуля. -
mainFields
: он сообщает Webpack, как искать модуль, когда мы импортируем модуль, но не пишем конкретное имя модуля. -
alias
: Когда у нас есть сторонние библиотеки или модули, на которые нужно ссылаться, мы можем напрямую импортировать их, настроив псевдонимы..min.js
файл, который можно разобрать непосредственно в библиотеке - разное
include
,exclude
,test
Взаимодействовать с загрузчиком для ограничения диапазона поиска файлов
параметр расширения
Как сказано выше,extensions
Он сообщает Webpack, как искать модули, когда мы импортируем модуль, но не записываем суффикс модуля. Такая ситуация очень распространена в нашей разработке, ситуация может быть следующей:
// 书写了模块后缀
import main from 'main.js'
// 没有书写模块后缀
import main from 'main'
Как и выше, мы не пишемmain.js
из.js
суффикс, потому что Webpack поможет нам найти некоторые файлы по умолчанию, и мы также можем настроить нашу собственную конфигурацию суффикса файла:
Параметр extensions должен максимально настроить только основные типы файлов, и не писать много ненужных файлов для удобства схемы, т.к. каждый дополнительный, нижний слой будет проходить работу по поиску файлов заново, что будет потребляют определенное количество производительности.
module.exports = {
// 其它配置
resolve: {
extensions: ['.js', '.json', '.vue']
}
}
Если мы настроим его, как указано выше, мы можем написать это в коде так:
// 省略 .vue文件扩展
import BaseHeader from '@/components/base-header';
// 省略 .json文件扩展
import CityJson from '@/static/city';
параметр mainFields
mainFields
Основной сценарий применения параметров заключается в том, что мы можем искать по Webpack, не прописывая конкретное имя модуля, возможна следующая ситуация:
// 省略具体模块名称
import BaseHeader from '@components/base-header/';
// 以上相当于这一段代码
import BaseHeader from '@components/base-header/index.vue';
// 或者这一段
import BaseHeader from '@components/base-header/main.vue';
Мы также можем настроить свои собственныеmainFields
параметр:
Как и в случае с параметром extensions, мы также не рекомендуем настраивать слишком много значений mainFields по вышеуказанным причинам.
module.exports = {
// 其它配置
resolve: {
extensions: ['.js', '.json', '.vue'],
mainFields: ['main', 'index']
}
}
псевдоним параметра
alias
Параметр больше похож на алиас.Если у вас модуль с глубокой директорией и длинным именем файла, полезно настроить алиас для удобства, для огромной сторонней библиотеки импортируйте напрямую.min.js
а не отnode_modules
Также отличное решение для внедрения в , возможна следующая ситуация:
Модули, настроенные через псевдонимы, повлияют на Tree Shaking. Рекомендуется использовать только библиотеки с сильной целостностью. Например, библиотеки lodash не рекомендуется импортировать через псевдонимы, потому что lodash больше подходит для использования Tree Shaking.
// 没有配置别名之前
import main from 'src/a/b/c/main.js';
import React from 'react';
// 配置别名之后
import main from 'main.js';
import React from 'react';
// 别名配置
const path = require('path');
module.exports = {
// 其它配置
resolve: {
extensions: ['.js', '.json', '.vue'],
mainFields: ['main', 'index'],
alias: {
main: path.resolve(__dirname, 'src/a/b/c'),
react: path.resolve(__dirname, './node_modules/react/dist/react.min.js')
}
}
}
Tree Shaking удаляет лишний код
Tree Shaking
Настройка Мы уже говорили об этом выше, настроитьTree Shaking
Тоже очень просто.
module.exports = {
// 其它配置
optimization: {
usedExports: true
}
}
если ты правTree Shaking
Я все еще не понимаю, пожалуйста, нажмитеTree ShakingПодробнее.
DllPlugin уменьшает количество компиляций сторонних библиотек
Для некоторых фиксированных сторонних библиотек, поскольку они фиксированные, каждый раз, когда мы их упаковываем, Webpack будет анализировать их код и упаковывать его. Так есть ли способ, давайте упакуем его только один раз, а результаты первого анализа будем использовать непосредственно для последующих упаковок. Ответ, конечно, да, мы можем использовать встроенный Webpack.DllPlugin
Чтобы решить эту проблему, решение этой проблемы можно разделить на следующие шаги:
- Упакуйте сторонние библиотеки отдельно в одну
xxx.dll.js
в файле - существует
index.html
используется вxxx.dll.js
документ - Результаты анализа упаковки сгенерированных сторонних библиотек хранятся в
xxx.manifest.json
в файле - когда
npm run build
При импорте результатов анализа уже упакованной сторонней библиотеки - оптимизация
Упакуйте сторонние библиотеки отдельно
Чтобы упаковать сторонние библиотеки отдельно, нам необходимо выполнить следующие шаги:
- Генерируется в корневом каталоге
dll
папка - существует
build
создать каталогwebpack.dll.js
конфигурационный файл и настройте его. - существует
package.json
файл, настроитьbuild:dll
Заказ - использовать
npm run build:dll
упаковать
генерироватьdll
папка:
$ mkdir dll
существуетbuild
создается в папкеwebpack.dll.js
:
$ cd build
$ touch webpack.dll.js
После создания необходимоwebpack.dll.js
Добавьте в файл следующий код:
const path = require('path');
module.exports = {
mode: 'production',
entry: {
vendors: ['lodash', 'jquery']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, '../dll'),
library: '[name]'
}
}
Наконец нужноpackage.json
Добавьте в файл новую команду упаковки:
{
// 其它配置
"scripts": {
"dev": "webpack-dev-server --config ./build/webpack.dev.js",
"build": "webpack --config ./build/webpack.prod.js",
"build:dll": "webpack --config ./build/webpack.dll.js"
}
}
использоватьnpm run build:dll
Результаты упаковки, ваши результаты упаковки будут выглядеть так:
|-- build
| |-- webpack.common.js
| |-- webpack.dev.js
| |-- webpack.dll.js
| |-- webpack.prod.js
|-- dll
| |-- vendors.dll.js
|-- src
| |-- index.html
| |-- index.js
|-- package.json
Цитироватьxxx.dll.js
документ
В предыдущем разделе мы успешно получилиxxx.dll.js
файл, то какindex.html
импортировать этот файл? Ответ - установитьadd-asset-html-webpack-plugin
Плагин:
$ npm install add-asset-html-webpack-plugin -D
существуетwebpack.common.js
используется вadd-asset-html-webpack-plugin
Плагин:
const addAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const configs = {
// 其它配置
plugins: [
new addAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll/vendors.dll.js')
})
]
}
module.exports = configs;
Мы предоставляем доступ к сторонней библиотеке по всему мируvendors
переменная, введенная сейчасxxx.dll.js
Результат файла выглядит следующим образом:
Создание упакованных файлов анализа
существуетwebpack.dll.js
с помощью встроенного WebpackDllPlugin
Плагин для анализа упаковки:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendors: ['lodash', 'jquery']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, '../dll'),
library: '[name]'
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, '../dll/[name].manifest.json')
})
]
}
Ссылка на упакованный файл анализа
существуетwebpack.common.js
с помощью встроенного WebpackDllReferencePlugin
Плагин для ссылки на файлы анализа пакетов:
const htmlWebpackPlugin = require('html-webpack-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
const addAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
module.exports = {
// 其它配置
plugins: [
new cleanWebpackPlugin(),
new htmlWebpackPlugin({
template: 'src/index.html'
}),
new addAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll/vendors.dll.js')
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll/vendors.manifest.json')
})
]
}
оптимизация
Теперь мы думаем о проблеме, которую мы сейчас ставимlodash
а такжеjquery
все упакованоvendors
файл, то что делать, если мы хотим разделить, и как настроить и импортировать после разделения? Возможный результат разделения выглядит следующим образом:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendors: ['lodash'],
jquery: ['jquery']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, '../dll'),
library: '[name]'
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, '../dll/[name].manifest.json')
})
]
}
Согласно приведенным выше результатам разделения, нам нужноwebpack.common.js
Создайте следующую эталонную конфигурацию в:
const htmlWebpackPlugin = require('html-webpack-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
const addAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const path = require('path');
const configs = {
// ... 其他配置
plugins: [
new cleanWebpackPlugin(),
new htmlWebpackPlugin({
template: 'src/index.html'
}),
new addAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll/vendors.dll.js')
}),
new addAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll/jquery.dll.js')
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll/vendors.manifest.json')
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll/jquery.manifest.json')
})
]
}
module.exports = configs;
Мы можем обнаружить, что по мере того, как мы внедряем все больше и больше сторонних модулей, мы постоянно модифицируем файл конфигурации Webpack. Для этой задачи мы можем использоватьNode
основной модульfs
анализироватьdll
Файлы под папкой импортируются динамически, по этой идее создаем новую.makePlugins
метод, который возвращает Webpackplugins
множество:
const makePlugins = function() {
const plugins = [
new cleanWebpackPlugin(),
new htmlWebpackPlugin({
template: 'src/index.html'
}),
];
// 动态分析文件
const files = fs.readdirSync(path.resolve(__dirname, '../dll'));
files.forEach(file => {
// 如果是xxx.dll.js文件
if(/.*\.dll.js/.test(file)) {
plugins.push(
new addAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, '../dll', file)
})
)
}
// 如果是xxx.manifest.json文件
if(/.*\.manifest.json/.test(file)) {
plugins.push(
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, '../dll', file)
})
)
}
})
return plugins;
}
configs.plugins = makePlugins(configs);
module.exports = configs;
использоватьnpm run build:dll
Упакуйте сторонние библиотеки, а затем используйтеnpm run build
Упаковка, результаты упаковки следующие:
В этом тесте время первой упаковки составляет 1100 мс+, а последующая упаковка стабильно составляет 800 мс+, что указывает на то, что наша оптимизация производительности Webpack вступила в силу.
|-- build
| |-- webpack.common.js
| |-- webpack.dev.js
| |-- webpack.dll.js
| |-- webpack.prod.js
|-- dist
| |-- index.html
| |-- jquery.dll.js
| |-- main.1158fa9f961c50aaea21.js
| |-- main.1158fa9f961c50aaea21.js.map
|-- dll
| |-- jquery.dll.js
| |-- jquery.manifest.json
| |-- vendors.dll.js
| |-- vendors.manifest.json
|-- src
| |-- index.html
| |-- index.js
|-- package.json
|-- postcss.config.js
резюме: Оптимизация производительности Webpack — это долгосрочная тема. Эта глава — лишь небольшой пример. В следующем блоге будет более подробная интерпретация Webpack, так что следите за обновлениями (установите флажок).
Напишите свой загрузчик
В нашем процессе использования Webpack мы используем многоloader
, то теloader
Откуда это? Можем ли мы написать свой собственныйloader
а потом использовать?
Ответ, конечно, да, Webpack предоставляет нам некоторыеloader
API, через который мы можем написать свой собственныйloader
и использовать.
Как написать и использовать свой загрузчик
Сцены:
нам нужно поставить.js
файл, все вхожденияWebpack is good!
, изменился наWebpack is very good!
. На самом деле нам нужно написать свой собственныйloader
, поэтому у нас есть следующие шаги, чтобы справиться с:
- новый
webpack-loader
проект - использовать
npm init -y
генерация командpackage.json
документ - Создайте
webpack.config.js
документ - Создайте
src
каталог и вsrc
новый каталогindex.js
- Создайте
loaders
каталог и вloader
новый каталогreplaceLoader.js
- Установить
webpack
,webpack-cli
Новый каталог проекта после вышеуказанных шагов выглядит следующим образом:
|-- loaders
| | -- replaceLoader.js
|-- src
| | -- index.js
|-- webpack.config.js
|-- package.json
Сначала вам нужноwebpack.config.js
Добавьте следующий код в:
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
module: {
rules: [
{
test: /\.js$/,
use: [path.resolve(__dirname, './loaders/replaceLoader.js')]
}
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
затем вpackage.json
добавление файлаbuild
Команда упаковки:
// 其它配置
"scripts": {
"build": "webpack"
}
следующий вsrc/index.js
Добавьте строку кода в файл: Этот файл использует простейший пример и просто печатает предложение.
console.log('Webpack is good!');
Наконец вloader/replaceLoader.js
написать свой собственныйloader
Код в файле:
- записывать
loader
час,module.exports
— это фиксированный способ записи, и это может быть только обычная функция, а не стрелочная функция (потому что она должна бытьthis
указывает на себя) -
source
является исходным содержимым упакованного файла
const loaderUtils = require('loader-utils');
module.exports = function(source) {
return source.replace('good', 'very good');
}
используйте нашloader
: использовать нашloader
, тебе следуетmodules
китайский языкloader
,resolveLoader
Он говорит Webpack использоватьloader
Когда, в какой каталог следует перейти, по умолчаниюnode_modules
, после этой конфигурации нам не нужно заполнять его путь, потому что он автоматически перейдет кloaders
Найдите ниже папку.
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
resolveLoader: {
modules: ['node_modules', './loaders']
},
module: {
rules: [
{
test: /\.js$/,
use: [{
loader: 'replaceLoader',
options: {
name: 'wanghuayu'
}
}]
}
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
Наконец мы бежимnpm run build
, в сгенерированномdist
открыть каталогmain.js
файл, вы можете видеть, что содержимое файла было успешно заменено, что указывает на то, что нашloader
Он был успешно использован.
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("console.log('Webpack is very good!');\n\n//# sourceURL=webpack:///./src/index.js?");
/***/ })
/******/ });
Как передать параметры в загрузчик и вернуть несколько значений
вопрос:
- Как мы можем вернуть несколько значений?
- Как мы передаем параметры нашему загрузчику?
Как вернуть несколько значений
API Webpack позволяет нам использоватьcallback(error, result, sourceMap?, meta?)
Возвращает несколько значений, имеет четыре параметра:
-
Error || Null
: тип ошибки, ошибка не переданаnull
-
result
: преобразованный результат -
sourceMap
: необязательный параметр, обрабатывающий проанализированныйsourceMap
-
meta
: необязательный параметр, метаинформация
Возвращает несколько значений, которые могут быть следующими:
// 第三,第四个参数是可选的。
this.callback(null, result);
Как передать параметры
мы знаем, что с помощьюloader
можно записать в следующем виде:
// options里面可以传递一些参数
{
test: /\.js$/,
use: [{
loader: 'replaceLoader',
options: {
word: 'very good'
}
}]
}
повторное использованиеoptions
После передачи параметров мы можем использовать официально предоставленныйloader-utilsполучитьoptions
параметры, которые можно записать следующим образом:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
var options = loaderUtils.getOptions(this);
return source.replace('good', options.word)
}
Как написать асинхронный код в Loader
В приведенных выше примерах мы все использовали синхронный код, поэтому, если у нас есть сцена, которая должна быть асинхронной, как ее реализовать? Мы могли бы также сделать такое предположение, сначала написавsetTimeout
:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
var options = loaderUtils.getOptions(this);
setTimeout(() => {
var result = source.replace('World', options.name);
return this.callback(null, result);
}, 0);
}
если ты побежишьnpm run build
Для упаковки будет сообщено об ошибке.Решение: используйтеthis.async()
Active ID имеет асинхронный код:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
var options = loaderUtils.getOptions(this);
var callback = this.async();
setTimeout(() => {
var result = source.replace('World', options.name);
callback(null, result);
}, 0);
}
На данный момент мы освоили, как писать, как ссылаться, как передавать параметры и как писать асинхронный код, в следующем разделе мы научимся писать свой собственныйplugin
.
Напишите свой собственный плагин
а такжеloader
Точно так же в процессе использования Webpack мы также часто используемplugin
, то мы научимся писать свои собственныеplugin
очень нужно.
Сценарий: написание собственногоplugin
Сцена после упаковкиdist
создать каталогcopyright.txt
документ
основы плагина
plugin
Основы рассказывают, как написать свой собственныйplugin
и как использовать, и создавать свои собственныеloader
Точно так же нам нужно создать следующую структуру каталогов проекта:
|-- plugins
| -- copyWebpackPlugin.js
|-- src
| -- index.js
|-- webpack.config.js
|-- package.json
copyWebpackPlugins.js
код в: использоватьnpm run build
При упаковке мы увидим вывод консолиhello, my plugin
Этот проход.
Плагин отличается от загрузчика Плагин требует от нас предоставить класс, что объясняет, почему мы должны выполнять новую операцию при использовании плагина.
class copyWebpackPlugin {
constructor() {
console.log('hello, my plugin');
}
apply(compiler) {
}
}
module.exports = copyWebpackPlugin;
webpack.config.js
код в:
const path = require('path');
// 引用自己的插件
const copyWebpackPlugin = require('./plugins/copyWebpackPlugin.js');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
// new自己的插件
new copyWebpackPlugin()
]
}
Как передать параметры
используя другиеplugin
При подключении нам часто нужно передать некоторые параметры, так как же мы передаем параметры в наши собственные плагины? Где это принято?
По сути, передача параметров плагина аналогична передаче параметров других плагинов, и объект передается в конструкторе.Передача параметров плагина выглядит следующим образом:
const path = require('path');
const copyWebpackPlugin = require('./plugins/copyWebpackPlugin.js');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
// 向我们的插件传递参数
new copyWebpackPlugin({
name: 'why'
})
]
}
существуетplugin
в вызове конструктора: используйтеnpm run build
Для упаковки мы можем распечатать значения параметров, которые мы передали в консолиwhy
class copyWebpackPlugin {
constructor(options) {
console.log(options.name);
}
apply(compiler) {
}
}
module.exports = copyWebpackPlugin;
Как написать и использовать свой собственный плагин
-
apply
Функция — это функция, которую необходимо выполнить при вызове нашего плагина. -
apply
параметр, относящийся к экземпляру Webpack -
compilation.assets
Информация об упакованном файле
Теперь у нас есть такое требование: использовать собственный плагин для генерации пакета в каталоге пакетов.copyright.txt
Файл с авторскими правами, так как написать такой плагин?
Сначала нам нужно знатьplugin
Функция ловушки, в соответствии с нашими правилами, вызывается функцией ловушки:emit
, который используется следующим образом:
class CopyWebpackPlugin {
constructor() {
}
apply(compiler) {
compiler.hooks.emit.tapAsync('CopyWebpackPlugin', (compilation, cb) => {
var copyrightText = 'copyright by why';
compilation.assets['copyright.txt'] = {
source: function() {
return copyrightText
},
size: function() {
return copyrightText.length;
}
}
cb();
})
}
}
module.exports = CopyWebpackPlugin;
использоватьnpm run build
После присвоения имени пакету мы видимdist
каталог, мы создали нашcopyright.txt
документ.
|-- dist
| |-- copyright.txt
| |-- main.js
|-- plugins
| |-- copyWebpackPlugin.js
|-- src
| |-- index.js
|-- webpack.config.js
|-- package.json
мы открытыcopyright.txt
файл со следующим содержимым:
copyright by why
Этот блог размещен на MOOC VideoОт основ до реального боя, я покажу вам, как освоить новую версию Webpack 4.0.Прочитайте и систематизируйте, пожалуйста, поддержите подлинную версию при просмотре видео.