24 примера для начала работы и освоения "Webpack4" (1)

Webpack

предисловие

Всего у этого предмета24Раздел, оглавление:

  1. Соберите проект и упакуйте файлы JS.
  2. Режим производства и разработки
  3. Переопределить ввод/вывод по умолчанию
  4. Транспиляция ES6 с помощью Babel 7
  5. Code Splitting
  6. Ленивая загрузка, предварительная выборка
  7. Автоматически генерировать файлы HTML
  8. Работа с файлами CSS/SCSS
  9. JS Tree Shaking
  10. CSS Tree Shaking
  11. Сводка по обработке изображения
  12. работа с файлами шрифтов
  13. Работа со сторонними библиотеками js
  14. Режим разработки и webpack-dev-сервер
  15. Режим разработки и режим производства・Настоящий бой
  16. Упаковка пользовательских функций
  17. Конфигурация ПВА
  18. Конфигурация TypeScript
  19. Конфигурация Эслинта
  20. Используйте DLLPlugin для ускорения упаковки
  21. Конфигурация многостраничной упаковки
  22. загрузчик записи
  23. Написать плагин
  24. Написать пакет

Первые 15 разделов основаны наWebpack4 прогрессивный учебникОсновываясь на моей собственной практике и понимании, спасибоСердечный загар😄

существуетWebpack4 прогрессивный учебникМодернизация на основе:

  • использоватьbabel7
  • настроить.browserslistrcдокумент
  • использоватьmini-css-extract-pluginзаменятьextract-text-webpack-plugin
  • использоватьoptimize-css-assets-webpack-pluginкомпрессияcss
  • использоватьpostcssдляcssплюс каждый префикс браузера
  • использоватьimage-webpack-loaderобрабатывать изображения

Последующие главы начинаются сmoocсетьРука об руку с вами, чтобы освоить новую версию Webpack4.0Организованные учебные заметки, спасибоDellLeeучитель 😄

Окружение выглядит следующим образом:

OS: 「win10」

node: 「10.5.0」

npm: 「6.1.0」

webpack: 「4.29.6」

webpack-cli: 「3.2.3」

Каждая глава соответствует демо 👉Адрес источника,Адрес сопроводительного документа, после клонирования исходного кода обратите внимание на запускnpm installУстановить зависимости

Я впервые пишу статью, надеюсь, вы укажете на не то место и исправите его как можно скорее.

1. Соберите проект и упакуйте файл JS.

адрес исходного кода demo1

Создайте пустую папку, инициализируйте, выполнив следующую командуpackage.json

npm init -y

npm init используется для инициализации нового файла package.json. Он задаст пользователю ряд вопросов, и если вы считаете, что вам не нужно изменять конфигурацию по умолчанию, просто нажмите Enter до конца. Если используется -y (для да), этап вопроса пропускается и создается новый файл package.json.

Представьте веб-пакет4:

npm i webpack --save-dev

Вам также понадобится webpack-cli, который представлен как отдельный пакет.Если вы не установите webpack-cli, вы не сможете использовать webpack в командной строке.

npm i webpack-cli --save-dev

Веб-версия этого проекта выглядит следующим образом:

"webpack": "^4.29.6",
"webpack-cli": "^3.2.3"

Теперь откройте package.json и добавьте скрипт сборки:

Попробуйте запустить и посмотрите, что произойдет:

npm run build

В версиях до webpack 4 точка входа должна была быть определена через атрибут entry в файле конфигурации с именем webpack.config.js, например:

Начиная с webpack4, больше не нужно определять точку входа: по умолчанию она будет./src/index.js

Чтобы протестировать эту новую функцию, сначала создайте файл ./src/index.js.

бежать сноваnpm run buildпытаться

Упаковка прошла успешно, и запакованная папка получена в текущем корневом каталоге, т.е.distпапка

Это выглядит./src/index.jsв качестве точки входа по умолчанию. Кроме того, это будет./dist/main.jsПакет среднего модуля вывода, текущий объем кода небольшой, вы можете отформатировать его, чтобы увидеть эффект

На этом заканчивается упаковка JS

Ссылаться на:Начало работы с официальным сайтом webpack

2. Режим производства и разработки

ДЕМО2 Адрес источника

Наличие 2 файлов конфигурации является распространенным шаблоном в webpack.

Типичный проект может иметь:

  • Файлы конфигурации для разработки, горячего обновления конфигурации, междоменной конфигурации, настройки портов и т. д.
  • Конфигурационные файлы для продакшна, настройка минимизации js, разделение кода и т. д.

В то время как для более крупных проектов может потребоваться 2 файла конфигурации, в webpack4 вы можете сделать это без единой строки конфигурации.

webpack4 представил режимы производства и разработки.

Внимательные друзья найдут вnpm run buildПосле упаковки будет сигнал тревоги

Параметр «режим» не установлен, веб-пакет вернется к «производственному». Установите для параметра «режим» значение «разработка» или «производство», чтобы включить значения по умолчанию для каждой среды. Вы также можете установить значение «none», чтобы отключить любое поведение по умолчанию.понять больше

  1. Откройте package.json и заполните раздел script следующим образом:
"dev": "webpack --mode development",
"build": "webpack --mode production"
  1. бегатьnpm run dev

Откройте файл ./dist/main.js, который является файлом бандла (пакета) и не сжат!

  1. бегатьnpm run build

Вы можете видеть, что файл ./dist/main.js был сжат.

На самом деле его можно найти и в терминале, посмотрев на размер сборки, размер файла в режиме dev 3,8 КБ, а размер файла в режиме prod всего 960 байт.

производственный режим включает различные оптимизации из коробки. Включает уплотнение, подъем объема, встряхивание деревьев и т. д.

С другой стороны, режим разработки оптимизирован для скорости и предоставляет только несжатый пакет.

В webpack4 все можно сделать без единой строчки конфигурации! Просто определите параметр --mode, чтобы получить все!

3. Переопределите ввод/вывод по умолчанию

адрес исходного кода demo3

1. Проверьте поддержку спецификации веб-пакета

webpack поддерживает спецификации ES6, CommonJS, AMD

Создайте папку поставщика с файлами minus.js, multi.js и sum.js, написанными в спецификациях CommonJS, AMD и ES6 соответственно.

// 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) {
  return a + b
}

существуетapp.jsВставьте указанные выше три файла js в файл

/**
 * webpack 支持 ES6、CommonJs 和 AMD 规范
 */

// ES6
import sum from './vendor/sum'
console.log('sum(1, 2) = ', sum(1, 2))

// CommonJs
var minus = require('./vendor/minus')
console.log('minus(1, 2) = ', minus(1, 2))

// AMD
require(['./vendor/multi'], function(multi) {
  console.log('multi(1, 2) = ', multi(1, 2))
})

2. Напишите файл конфигурации для переопределения ввода/вывода

webpack.config.js — это веб-пакетПо умолчаниюИмя конфигурационного файла, созданного в корневом каталоге

const path = require('path')

module.exports = {
  entry: {
    app: './app.js' // 需要打包的文件入口
  },
  output: {
    publicPath: __dirname + '/dist/', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: 'bundle.js' // 打包后生产的 js 文件
  }
}

path.resolve()Метод преобразует путь или последовательность фрагментов пути в абсолютный путь.

__dirname: Имя папки текущего модуля.

можно использоватьconsole.logПросто выведите это

const path = require('path')

console.log('__dirname: ', __dirname)
console.log('path.resolve: ', path.resolve(__dirname, 'dist'))

module.exports = {
  entry: {
    app: './app.js' // 需要打包的文件入口
  },
  output: {
    publicPath: __dirname + '/dist/', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: 'bundle.js' // 打包后生产的 js 文件
  }
}

воплощать в жизньnpm run buildупаковать js-файл

Вы обнаружите, что создается папка dist и создаются два упакованных файла.

Это связано с тем, как AMD была представлена: если вы закомментируете запись AMD в app.js, будет упакован только один файл bundle.js.

При написании кода лучше всего использовать спецификации ES6 и CommonJS.

Когда вы комментируете AMD, после упаковки в dist есть несколько файлов, потому что при упаковкеСначала не удалял файл dist, а затем пакет, нам нужно использовать плагин, чтобы сделать это за нас, ссылка на GitHub:clean-webpack-plugin

① Установите плагин

npm install clean-webpack-plugin --save-dev

② Измените файл конфигурации веб-пакета.

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  entry: {
    app: './app.js' // 需要打包的文件入口
  },
  output: {
    publicPath: __dirname + '/dist/', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: 'bundle.js' // 打包后生产的 js 文件
  },
  plugins: [
    new CleanWebpackPlugin() // 默认情况下,此插件将删除 webpack output.path目录中的所有文件,以及每次成功重建后所有未使用的 webpack 资产。
  ]
}

ВНИМАНИЕ!Если установленный плагин clean-webpack-plugin3.0версии, конфигурация должна быть изменена на:

// common js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

выполнить позжеnpm run buildпросто хорошо

Упакованный файл js будет помещен в каталог dist в соответствии с нашей конфигурацией,Создайте html-файл, который ссылается на упакованный файл js., откройте F12, чтобы увидеть эффект

Справочная статья

Серия руководств webpack4 (1): упаковка JS

Учебное пособие по Webpack4: от нулевой конфигурации к рабочему режиму

4. Транспиляция ES6 с помощью Babel 7

адрес исходного кода demo4

(1) Понять Вавилон и его экологию

Современный Javascript в основном написан на ES6. Но не каждый браузер знает, как обращаться с ES6. Нам нужно какое-то преобразование, и этот шаг преобразования называется транспилированием. Транспиляция относится к использованию синтаксиса ES6 для перевода в поведение, понятное старым браузерам.

Webpack не знает, как выполнить преобразование, но имеетпогрузчик: относиться к ним как к транспиляторам.

babel-loaderЯвляется загрузчиком веб-пакетов (загрузчиком) для транспиляции ES6 и выше в ES5.

Для началаloader, нам нужно установить кучу зависимостей, следующееBabel7Господин,Предложение по обновлению

  • @babel/core
  • @babel/preset-env: содержит правила преобразования синтаксиса для ES6, 7 и т. д.
  • @babel/plugin-transform-runtime: избегайте загрязнения глобальных переменных полифиллом и уменьшайте размер упаковки.
  • @babel/polyfill: Встроенные прокладки преобразования методов и функций ES6.
  • babel-loader: отвечает за преобразование синтаксиса ES6

Если вы выполняете транспиляцию с помощью babel7, вам необходимо установить@babel/core,@babel/preset-envа также@babel/plugin-transform-runtimeвместо babel-core, babel-preset-env и babel-plugin-transform-runtime, которые предназначены для babel6.

Причины использовать @babel/plugin-transform-runtime: Babel использует очень маленькие помощники для общих функций. По умолчанию это будет добавлено к каждому файлу, который в этом нуждается.Это повторение иногда не нужно, особенно если ваше приложение распределено по нескольким файлам.transform-runtimeПрограммный код, введенный Babel, можно повторно использовать дляСохранить код и уменьшить размер.

Причины использования @babel/polyfill: Babel по умолчанию преобразует только новый синтаксис (синтаксис) JavaScript, а не новые.API,НапримерГлобальные объекты, такие как Iterator, Generator, Set, Maps, Proxy, Reflect, Symbol, Promise и т. д.и некоторые методы, определенные для глобального объекта (например,Object.assign) не будет перекодирован. должен использовать@babel/polyfill, который обеспечивает прокладку для текущей среды. Так называемая прокладка призвана сгладить разницу между разными браузерами или разными средами.

(2) Установите зависимости и настройте

① Зависимости установки

npm i @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime --save-dev
npm i @babel/polyfill @babel/runtime

② В корневом каталоге проекта создайте файл с именем.babelrcновый файл для настройкиBabel:

{
  "presets": ["@babel/preset-env"],
  "plugins": ["@babel/plugin-transform-runtime"]
}

Спасибо за раздел комментариевxcswebОтмечается, что если вы столкнулись со следующей ошибкой


WARNING: We noticed you're using the `useBuiltIns` option without declaring a core-js version. Currently, we assume version 2.x when no version is passed. Since this default version will likely change in future versions of Babel, we recommend explicitly setting the core-js version you are using via the `corejs` option. 
 
You should also be sure that the version you pass to the `corejs` option matches the version specified in your `package.json`'s `dependencies` section. If it doesn't, you need to run one of the following commands: 
 
  npm install --save core-js@2    npm install --save core-js@3 
  yarn add core-js@2              yarn add core-js@3

Не только для установки npm install --save core-js@3, но и для установки .babelrc set "corejs": 3

{
 "presets": [
   [
     "@babel/preset-env",
     {
       "useBuiltIns": "usage",
       "corejs": 3
     }
   ]
 ],
 "plugins": ["@babel/plugin-transform-runtime"]
}

③ загрузчик конфигурации webpack (загрузчик)

module: {
  rules: [
    {
      test: /\.js$/, // 使用正则来匹配 js 文件
      exclude: /node_modules/, // 排除依赖包文件夹
      use: {
        loader: 'babel-loader' // 使用 babel-loader
      }
    }
  ]
}

Окончательная конфигурация webpack.config.js:

④ Внедрить глобально в app.js@babel/polyfillи написать синтаксис ES6 и выполнитьnpm run buildПакет

// 全局引入
import '@babel/polyfill'

// 测试 ES6 语法是否通过 babel 转译
const array = [1, 2, 3]
const isES6 = () => console.log(...array)

isES6()

const arr = [new Promise(() => {}), new Promise(() => {})]

arr.map(item => {
  console.log(item)
})

5 после упаковкиИспользуйте браузер IEОткройте файл index.html, чтобы увидеть, есть ли вывод в консоли.Если это новая версия Chrome, вы можете использовать синтаксис es6, поэтому используйтеIEэтоКорень всех золпытаться

глобальный импорт@babel/polyfillЭтот способ импорта полифилов, которые не нужны в коде, может увеличить размер пакета.

Изменять.babelrc, переводить только то, что мы используем

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage"
      }
    ]
  ],
  "plugins": ["@babel/plugin-transform-runtime"]
}

При этом закомментируйте глобальное введение этого кода и снова упакуйте его

// 全局引入
// import '@babel/polyfill'

Объем значительно уменьшен, но в большинстве случаев мы не знаем точно конкретных причин проблем совместимости в проекте, поэтомуЛучше импортировать по всему миру

(3) Разберитесь с файлом конфигурации .browserslistrc

browserslistrcКонфигурация для совместного использования целевого браузера и версии Node.js между различными внешними инструментами

Проверить список браузеровСтраницы, совместимые с браузером

когда вы добавляете следующее вpackage.json, все инструменты автоматически найдут целевой браузер:

"browserslist": [
  "> 1%",
  "last 2 version",
  "not ie <= 8"
]

также может создать.browserslistrcКонфигурация записи файла отдельно

# 所支持的浏览器版本

> 1% # 全球使用情况统计选择的浏览器版本

last 2 version # 每个浏览器的最后两个版本

not ie <= 8 # 排除小于 ie8 以下的浏览器

В проекте до сих пор используетсяСоздавайте профили индивидуальноЭто легко понять, если вы считаете, что файл конфигурации не очень хорош, вы также можете написать его вpackage.jsonсередина

Справочная статья

Серия руководств webpack4 (2): Компиляция ES6

Личное понимание использования babel 7

совет по обновлению babel 7

browserslist

5. Разделение кода

адрес исходного кода demo5

package.jsonЗависимости, используемые файлом npm install install:

{
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  },
  "devDependencies": {
    "clean-webpack-plugin": "^2.0.0",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  },
  "dependencies": {
    "lodash": "^4.17.11"
  }
}

Мы создаем файл index.js в папке src/

import _ from 'lodash'

console.log(_.join(['a', 'b', 'c']))

Структура каталогов:

Настройте файл webpack.config.js

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  entry: {
    main: './src/index.js'
  },
  output: {
    publicPath: __dirname + '/dist/', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  plugins: [new CleanWebpackPlugin()]
}

бегатьnpm run buildПакет

Используйте упакованный файл в 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>
    <script src="./dist/main.bundle.js"></script>
  </body>
</html>

Открыть в браузереindex.htmlфайл, войдите в консоль, вы увидите следующую информацию:a,b,c

Если мы снова изменим бизнес-код, измените код в index.js на

import _ from 'lodash'

console.log(_.join(['a', 'b', 'c'], '***'))

Переупакуйте, обновите страницу, чтобы увидетьa***b*****c**

Сторонний фреймворк, на который мы ссылаемся, упакован с нашим бизнес-кодом, так в чем же проблема?

Предположим, что lodash равен 1M, бизнес-код также равен 1M, а после упаковки предполагается, что он равен 2M.

Каждый раз, когда браузер открывает страницу, он должен загрузить файл размером 2 МБ, прежде чем сможет отобразить бизнес-логику, что увеличит время загрузки.

Обновление бизнес-кода будет сравниватьчасто, сторонний код в принципе не изменится, поэтому после переупаковки, при условии, что это 2M, после того, как пользователь снова откроет веб-страницу, файл 2M будет загружен снова.

браузер имееттайникДа, если файл не изменился, вам не нужно отправлять http-запрос, а получить его прямо из кеша, что может ускорить скорость загрузки страницы при обновлении страницы или входе на нее во второй раз.

Как это решить, вы можете использовать разделение кода в веб-пакете

До того, как webpack4 использовалcommonsChunkPluginразделить общий код, который был заменен после v4заброшенныйи использоватьsplitChunksPlugins

Прежде чем использовать splitChunksPlugins, сначала узнайте, что splitChunksPlugins — это модуль подразделения в основном модуле веб-пакета.Не требуется импорт npm

Теперь давайте настроимwebpack.config.jsдокумент

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  entry: {
    main: './src/index.js'
  },
  output: {
    publicPath: __dirname + '/dist/', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  plugins: [new CleanWebpackPlugin()]
}

Выделенный фрагмент кода выше указывает веб-пакету выполнить разделение кода, вотchunks: 'all'заключается в разделении всего кода, включая синхронный код и асинхронный код, по умолчанию webpackchunks: 'async'сегментацияасинхронныйкод

Мы используемnpm run devупаковать код в среде разработки, чтобы кодне будет сжиматься, что нам удобно наблюдать, мы видим, что код разбит на два файла

Открытьdist/main.bundle.jsвы можете увидеть файл src/index.js внизу, который содержит код для бизнес-логики, но нет кода для lodash

Открытьdist/vendors~main.jsфайл, вверху вы видите модуль lodash

Откройте страницу снова, и консоль также выводит содержимое, что достигаетсяCode Splitting(разделение кода)

На самом деле, когда нет вебпака, тоже есть разбиение кода, но нам нужно вручную разбить его самим, а сейчас мы используем вебпак, через этот пункт конфигурации, он автоматически поможет нам сделать разбиение кода

Посмотрите внимательно на раздельное кодовое имя,vendors~main.js, вносим изменения в имя сплита

еще вsplitChunksв пункте конфигурации добавитьcacheGroupsобъект

optimization: {
  splitChunks: {
    chunks: 'all',
    cacheGroups: {
      vendors: {
        name: 'vendors'
      }
    }
  }
}

Вы можете увидеть эффект, когда снова упакуете его.cacheGroupsКонфигурация по умолчанию будет определятьvendorsа такжеdefault

test: /[\\/]node_modules[\\/]/,Использование обычной фильтрации толькоnode_modulesПредставленные сторонние библиотеки будут разделены

Чтобы проверить конфигурацию по умолчанию, мы устанавливаем для свойства splitChunks пустой объект и снова упаковываем

После упаковки обнаружил, что файл всего один, почему так?

потому чтоchunksПо умолчаниюasync, будет только разделятьсяасинхронный, и раньше мы писали синхронный код, сначала импортировали lodash, а потом писали бизнес-логику, теперь делаем это асинхронно, и меняем код в index.js на следующий:

function getComponent() {
  // 使用 异步的形式导入 lodash,default: _ 表示用 _ 代指 lodash
  return import('lodash').then(({ default: _ }) => {
    var element = document.createElement('div')
    element.innerHTML = _.join(['hello', 'world'], '-')
    return element
  })
}

getComponent().then(element => {
  document.body.appendChild(element)
})

разделенный здесь0.jsа такжеmain.bundle.js, 0 назван с идентификатором в качестве числа

Поэтому обычно мы устанавливаем куски для всех, и упаковывается как асинхронный, так и синхронный код.

Теперь давайте скопируем конфигурацию по умолчанию с официального сайта webpack в наш webpack.config.js для анализа.

optimization: {
  splitChunks: {
    chunks: 'async',
    minSize: 30000,
    maxSize: 0,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',
    name: true,
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      }
    }
  }
}

Конфигурация разделения кода вебпака такая, например, если мы хотим разделить сторонние библиотеки, такие как jQuery и lodash, то сначала он пройдет черезchunks、minSize、maxSize、minChunksПодождите, после выполнения условий сгенерируйте два файла, jQuery и lodash, и поместите их вcacheGroupкэшируется вcacheGroupнастроен вГруппаЧтобы решить, следует ли интегрировать два файла в один пакет файлов или упаковать их отдельно, например, в приведенном выше кодеvendors, этоnode_modulesВсе сторонние библиотеки упакованы вvendors.jsфайл, если вы хотите продолжить разделение, вы можете сделать это

cacheGroups: {
  lodash: {
    name: 'lodash',
    test: /[\\/]node_modules[\\/]lodash[\\/]/,
    priority: 5  // 优先级要大于 vendors 不然会被打包进 vendors
  },
  vendors: {
    test: /[\\/]node_modules[\\/]/,
    priority: -10
  },
  default: {
    minChunks: 2,
    priority: -20,
    reuseExistingChunk: true
  }
}

Спасибо за раздел комментариевanlinsirУказано, что если есть ошибка в упаковкеПоддержка экспериментального синтаксиса «dynamicImport» в настоящее время не включена.,Это потому чтоdynamicImportЭто все еще экспериментальный синтаксис, веб-пакет его не поддерживает, вам необходимо установить плагины для его поддержки. Конкретные шаги см.блог woo woo woo.cn на.com/beyond its/afraid…

Снова упакуйте его, и вы увидите, что lodash разделен. Позже сторонние библиотеки могут быть разбиты на js-файл с этой конфигурацией, напримерelement-ui,УведомлениенастраиватьpriorityЗначение очень важно, чем выше приоритет, тем быстрее будет упакован пакет.

Если index.js вводит A.js и B.js, а A и B также вводят общий, общий вводится дважды, и его можно назвать общим модулем.

Структура каталогов:

код показывает, как показано ниже:

// a,js
import './common'
console.log('A')
export default 'A'

// b.js
import './common'
console.log('B')
export default 'B'

// common.js
console.log('公共模块')
export default 'common'

// index.js
// 异步代码
import(/* webpackChunkName: 'a'*/ './a').then(function(a) {
  console.log(a)
})

import(/* webpackChunkName: 'b'*/ './b').then(function(b) {
  console.log(b)
})

// 异步代码
function getComponent() {
  // 使用异步的形式导入 lodash,default: _ 表示用 _ 代指 lodash
  return import('lodash').then(({ default: _ }) => {
    var element = document.createElement('div')
    element.innerHTML = _.join(['hello', 'world'], '-')
    return element
  })
}

getComponent().then(element => {
  document.body.appendChild(element)
})

тот, что вышеасинхронныйСпособ написания может быть более запутанным, теперь упростите его, и веб-пакет прав.асинхронный кодпройти черезПримечанияВы можете напрямую изменить имя пакета. Следующие коды представлены в асинхронной форме.

// 异步代码
import(/* webpackChunkName: 'a'*/ './a').then(function(a) {
  console.log(a)
})

import(/* webpackChunkName: 'b'*/ './b').then(function(b) {
  console.log(b)
})

import(/* webpackChunkName: 'use-lodash'*/ 'lodash').then(function(_) {
  console.log(_.join(['1', '2']))
})

Установите для minChunks значение 2, минимальное общее значение 2 раза для разделения

optimization: {
  splitChunks: {
    chunks: 'all',
    minSize: 30000,
    maxSize: 0,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',
    name: true,
    cacheGroups: {
      lodash: {
        name: 'lodash',
        test: /[\\/]node_modules[\\/]lodash[\\/]/,
        priority: 10
      },
      commons: {
        name: 'commons',
        minSize: 0, //表示在压缩前的最小模块大小,默认值是 30kb
        minChunks: 2, // 最小公用次数
        priority: 5, // 优先级
        reuseExistingChunk: true // 公共模块必开启
      },
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      }
    }
  }
}

разделенный здесьlodashи мы определили в комментарияхuse-lodash, первая — это третья библиотека, а вторая — бизнес-код, написанный с использованием третьей библиотеки, которую также можно разделить

Причина, по которой здесь автоматически вводятся разделенные зависимости, вы можете просмотреть в упакованном видеmain.bundle.jsдокумент

Даже мы можем разбить точку, чтобы увидеть, как это работает, ниже приведена демонстрация анимации gif.

Наиболее часто используемые элементы конфигурации приведены в таблице ниже.Дополнительные сведения о конфигурации см.Официальный сайт

элемент конфигурации иллюстрировать Пример
chunks тип соответствующего блока initial (начальный фрагмент), async (асинхронные фрагменты, загружаемые по запросу), all (все фрагменты)
name Используется для управления именованием отдельных блоков кода. chunk-libs
test Расположение файла для указания совпадений групп кэша /[\/]node_modules[\/]/
priority Приоритет правила разделения, чем выше приоритет, тем первым будет соответствовать priority: 20
minSize Сжатие сверх размера minSize: 30000 Значение по умолчанию — 30 КБ.
minChunks Минимальное количество блоков, которые должны совместно использовать модули перед разделением minChunks: 2
reuseExistingChunk Если текущий блок был отделен от основного модуля, он будетПовторное использованиевместо этого он генерирует новые куски true

Справочная статья

Серия руководств webpack4 (3): многостраничное решение — извлечение общего кода

официальный сайт вебпака

6. Ленивая загрузка, предварительная выборка

адрес исходного кода demo6

Измените файл index.js на основе demo5 и удалите лишние файлы js.

document.addEventListener('click', function() {
  import(/* webpackChunkName: 'use-lodash'*/ 'lodash').then(function(_) {
    console.log(_.join(['3', '4']))
  })
})

Этот код означает, что когда нажата страница, Lodash загружена асинхронно и содержимое выводится, а файл index.html открывается после упаковки. Демонстрация выглядит следующим образом:

Когда я захожу на страницу в первый раз, lodash и use-lodash не загружаются, когда я нажимаю на веб-страницу, браузер снова загружает ее, а консоль выводит содержимое, это кодленивая загрузка, если используетсяvue-routerдрузья должны знатьОтложенная загрузка маршрута, и официальный также рекомендует использовать ленивую загрузку, просто для объединения веб-пакета, на следующем рисунке показан проект, сгенерированный vue-cli3.

На самом деле ленивая загрузка происходит черезimportЧтобы загрузить модуль асинхронно, когда его загружать, это должно быть написано в соответствии с бизнесом, например, компоненты всплывающего окна, компоненты модального окна и т. д., все они появляются после нажатия кнопки.

Ленивая загрузка может ускорить загрузку веб-страниц.Если вы упаковываете все страницы, такие как страницы сведений и всплывающие окна, в файл js, если пользователи посещают только домашнюю страницу, им нужен только код домашней страницы, и не нужен код других страниц и добавить дополнительный код, это только увеличит время загрузки, поэтому мы можем лениво загружать маршрут и загружать соответствующий модуль только тогда, когда пользователь обращается к соответствующему маршруту

Ленивая загрузка — это концепция не в webpack, а в ES6.importСинтаксис, webpack может распознавать только синтаксис импорта и выполнять сегментацию кода.

То, что возвращается после импорта, — это then, указывающее, что этоpromiseтип, некоторые недорогие браузерыне поддерживаетсяобещания, напримерIE, если вы хотите использовать этот асинхронный код, вам нужно использоватьbabelтак же какbabel-polyfillсделать преобразование, потому что я использую версию 73chromeБраузер поддерживает синтаксис ES6, поэтому я могу использовать его без установки babel.

Измените файл index.js

document.addEventListener('click', function() {
  const element = document.createElement('div')
  element.innerHTML = 'Hello World'
  document.body.appendChild(element)
})

Перепакуйте и откройте index.html , откройте консоль браузера, нажмитеctrl + shift + p,войтиcoverage

Вы можете увидеть неиспользованную скорость кода js, загруженного на текущей странице, а красная область представляет собой неиспользуемый сегмент кода.

Демо:

ОткрытьcoverageЕсли анализируемый файл не отображается, не забудьте обновить его

Здесь код в красной области сначала не используется, когда я нажимаю на страницу, она становится зеленой и появляется страницаHello WorldУказание того, что код используется

Когда страница только что загружена, асинхронный код вообще не будет выполняться, но если мы его загрузим, это фактически приведет к потере производительности выполнения страницы.Webpack надеется взаимодействовать с такими функциями, и его следует поместить в асинхронную загрузку. . модуль для записи

Создайте новый файл click.js

function handleClick() {
  const element = document.createElement('div')
  element.innerHTML = 'Dell Lee'
  document.body.appendChild(element)
}

export default handleClick

И измените файл index.js для асинхронной загрузки модуля:

document.addEventListener('click', () => {
  import('./click.js').then(({ default: func }) => {
    func()
  })
})

переупаковывать, использоватьcoverageанализировать

Демо:

Когда страница загружается, бизнес-логика не загружается.При нажатии на страницу загружается модуль 1.js, который мы представили асинхронно в index.js.

Такой способ написания кода — самый быстрый способ загрузки страниц.Дело не в кешировании, а в использовании кода

Поэтому в процессе упаковки веб-пакета мы надеемся, что сможем написать больше асинхронного кода для повышения производительности веб-сайта, поэтому фрагменты в разделенных фрагментах веб-пакета по умолчанию являются асинхронными, асинхронными.

Асинхронный код может повысить производительность открытия вашей веб-страницы, а синхронный код должен добавить кеш, улучшение производительности очень ограничено, потому что кеш обычноОткройте страницу второй раз или обновите страницукеш полезен, но производительность веб-страницы, как правило, зависит от пользователя.Открытие веб-страницы в первый раз, глядя на первый экран.

Конечно, будет и другая проблема, то есть когда пользователь нажимает, загружается бизнес-модуль, если бизнес-модуль относительно большой, пользователь не видит эффект сразу после нажатия, а ждет несколько секунд, так что опыт это не хорошо, как решить эту проблему

Первый: если вы посещаете домашнюю страницу, вам не нужно загружать логику страницы сведений.После загрузки домашней страницы пользователя страница будет отображаться, пропускная способность страницы будет освобождена, и сеть будет отключена. быть бездействующим, поэтому вы можете «тайно» загрузить страницу сведений, а не загружать ее, когда пользователь нажимает

Это решение основано на веб-пакетеPrefetching/Preloadingхарактеристика

Изменить index.js

document.addEventListener('click', () => {
  import(/* webpackPrefetch: true */ './click.js').then(({ default: func }) => {
    func()
  })
})

webpackPrefetch: trueОн будет ждать загрузки вашего основного JS, а когда пропускная способность сети будет простаивать, он загрузит его для вас заранее.

Обновите страницу после перепаковки, обратите внимание наNetwork

Когда веб-страница открыта, main.bundle.js загружается, а сеть простаивает. Предварительная загрузка 1.js занимает 14 мс. Когда я нажимаю на страницу, в сети есть еще один 1.js, который занимает 2 мс. , это потому что 1.js загружается в первый раз, и он кешируется браузером, когда я нажимаю, браузер напрямую извлекает его из кеша, и скорость отклика очень высокая

Здесь мы используемwebpackPrefetch, а другой естьwebpackPreload

По сравнению с предварительной выборкой директива Preload имеет многоразница:

Prefetch

Для оптимизации дело не только в кеше, улучшение производительности кода, которое может принести кеш, очень ограничено, но и в том, как сделать кодПрименениеСамое высокое, некоторый код, который используется после взаимодействия, может быть записан в асинхронный компонент, а логика кода загружается в виде ленивой загрузки, что сделает скорость доступа к странице быстрее.Если вы думаете, что ленивая загрузка повлияет на пользовательский опыт , вы можете использовать Prefetch для предварительной загрузки, но в некоторых браузерахнесовместимый, будут проблемы с совместимостью, фокус не на том, как использовать Prefetch, а на оптимизации производительности фронтенд-кода,Кэширование не самый важный момент, самое главное это покрытие использования кода (coverage)

7. Автоматически генерировать файлы HTML

адрес исходного кода demo7

Считаете ли вы, что после операций, описанных в приведенных выше разделах, каждый раз изменять файл js, представленный в index.html, очень проблематично? После изменения имени пакета вы также должны соответствующим образом изменить имя js, представленное в index.html. Чтобы использовать плагин, чтобы помочь нам, после упаковкиАвтоматически генерировать файлы HTML,И автоматически импортируйте упакованный файл js

(1) Зависимости установки

npm i html-webpack-plugin html-loader --save-dev

package.json выглядит следующим образом:

{
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  },
  "devDependencies": {
    "clean-webpack-plugin": "^2.0.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  },
  "dependencies": {
    "lodash": "^4.17.11"
  }
}

(2) Измените файл конфигурации

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动生成 HTML',
      minify: {
        // 压缩 HTML 文件
        removeComments: true, // 移除 HTML 中的注释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 压缩内联 css
      },
      filename: 'index.html', // 生成后的文件名
      template: 'index.html' // 根据此模版生成 HTML 文件
    })
  ]
}

HtmlWebpackPluginОн настраивается в опции плагина. Общие параметры имеют следующие значения:

  • title: заголовок html, сгенерированный после упаковки
  • имя файла: имя упакованного html файла
  • template: файл шаблона (index.html в корневом каталоге исходного кода примера)
  • куски: соответствует конфигурации записи, поддерживает несколько страниц и несколько записей
  • minify: параметры сжатия

из-за использованияtitleвариант, вам нужноtemplateДобавить в заголовок html соответствующий параметру<%= htmlWebpackPlugin.options.title %>

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入插件

module.exports = {
  entry: {
    page: './src/page.js'
  },
  output: {
    publicPath: __dirname + '/dist/', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].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 文件
    })
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        lodash: {
          name: 'chunk-lodash', // 单独将 lodash 拆包
          priority: 10, // 优先级要大于 commons 不然会被打包进 commons
          test: /[\\/]node_modules[\\/]lodash[\\/]/
        },
        commons: {
          name: 'chunk-commons',
          minSize: 1, //表示在压缩前的最小模块大小,默认值是 30kb
          minChunks: 2, // 最小公用次数
          priority: 5, // 优先级
          reuseExistingChunk: true // 公共模块必开启
        }
      }
    }
  }
}

(3) Упаковка и тестирование

бегатьnpm run build

Откройте автоматически созданный index.html в папке dist.

Откройте файл index.html в браузере, откройте консоль и обнаружите, что есть вывод, ОК, файл HTML успешно сгенерирован автоматически.

Осторожные друзья могут найти проблему, JS, представленный в сгенерированном файле HTML,абсолютный путь, но после того, как реальный проект запакован, он развертывается на сервере.Использовать абсолютный путь точно нельзя, потому что абсолютный путь вашего локального компьютера не может быть найден на сервере.

Файл js, который мы хотим импортироватьИзменение абсолютного пути на относительный путь

Измените файл webpack.config.js.

Найдите выходную конфигурацию вывода, измените общедоступный путь publicPath и измените его на./абсолютный путь

  output: {
    publicPath: './', // js 引用的路径或者 CDN 地址
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },

Упакуйте его еще раз, посмотрите упакованный файл index.html и откройте браузер для проверки, это не проблема.

8. Обработка файлов CSS/SCSS

адрес исходного кода demo8

(1) Подготовка

Распространенные способы импорта CSS в HTML:<link>этикетки и<style>Существует два типа тегов, поэтому на этот раз они сочетаются с характеристиками веб-пакета для достижения следующих функций:

  • Внедрить css через тег ссылки
  • поместите css в тег стиля

На следующем рисунке показана структура кода каталога на этот раз:

На этот раз нам нужно использоватьcss-loader,style-loaderПодождите, пока загрузчик, такой как babel, webpack не знает, как извлечь CSS в файлы. Необходимо использовать загрузчик для загрузки соответствующего файла

css-loader: отвечает за синтаксический анализ кода CSS, в основном для обработки зависимостей в CSS, таких как объявления @import и url(), которые ссылаются на внешние файлы.

style-loader преобразует результат, проанализированный css-loader, в код JS при запускеЯрлык стиля динамической вставкичтобы код CSS работал.

(2) Зависимости установки

npm i css-loader style-loader --save-dev

package.jsonследующим образом:

{
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  },
  "devDependencies": {
    "clean-webpack-plugin": "^2.0.0",
    "css-loader": "^2.1.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.5.0",
    "style-loader": "^0.23.1",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  }
}

изменить файл конфигурации

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/, // 针对 .css 后缀的文件设置 loader
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}

Настройте свойство rules в модуле, например, при настройке babel, сначала используйте обычные правила в тесте для фильтрации.cssфайл, да.cssфайл с помощью загрузчика,'style-loader', 'css-loader'

Пишите стили в base.css

*,
body {
  margin: 0;
  padding: 0;
}
html {
  background: red;
}

И внедрить base.css в app.js

import style from './css/base.css'

Полный код конфигурационного файла:

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' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.css$/, // 针对 .css 后缀的文件设置 loader
        use: ['style-loader', 'css-loader'] // 使用 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 入口才会被打包
    })
  ]
}

Упаковка проекта, просмотр папки dist

обнаружить иНе создается файл CSS, но открытие index.html оформлено в стиле

Причина в следующем:style-loader, css-loaderПосле обработки двух загрузчиков код CSS будет преобразован в JS и упакован с помощью index.js.

можно найти по<style>css для внедрения тегов

Если нам нужно отделить файл CSS отдельно, нам нужно использоватьmini-css-extract-pluginплагин.

использовалextract-text-webpack-pluginплагин, этот плагин не совсем соответствует webpack4, теперь используйтеmini-css-extract-plugin

Обязательно обновите веб-пакет до4.2.0версии и выше. иначеmini-css-extract-pluginбудет недействительным!

ещеГорячее обновление не поддерживается, то есть, если вы меняете css в среде разработки, вам нужно вручную обновить страницу, чтобы увидеть эффект. В настоящее время этот плагин обычно используется в производственной среде, и «style-loader» по-прежнему используется в среде разработки.Подробнее см.Официальная конфигурация сайта

npm i mini-css-extract-plugin --save-dev

Измените файл конфигурации:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/, // 针对 .css 后缀的文件设置 loader
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    })
  ]
}

Полный код:

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$/, // 针对 .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, но он не сжимается, импортируяoptimize-css-assets-webpack-pluginПлагин для реализации сжатия css

npm install optimize-css-assets-webpack-plugin --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 OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-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$/, // 针对 .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'
    }),
    new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css$/g,
      cssProcessor: require('cssnano'), //用于优化\最小化 CSS 的 CSS处理器,默认为 cssnano
      cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给 cssProcessor 的选项,默认为{}
      canPrint: true //布尔值,指示插件是否可以将消息打印到控制台,默认为 true
    })
  ]
}

Когда вы снова открываете файл css, вы можете обнаружить, что он был сжат, а открытие index.html также оформлено в стиле

(3) Обработка файлов SCSS

Зависимость установки sass:

npm i node-sass sass-loader --save-dev

Добавьте папку scss и файл main.scss в папку src.

стиль импорта main.scss

$bgColor: black !default;
*,
body {
  margin: 0;
  padding: 0;
}
html {
  background-color: $bgColor;
}

Добавьте файл main.scss в app.js.

import './css/base.css'
import './scss/main.scss'

Изменить файл конфигурации

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 OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-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: /\.(scss|css)$/, // 针对 .scss 或者 .css 后缀的文件设置 loader
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          'css-loader',
          'sass-loader' // 使用 sass-loader 将 scss 转为 css
        ]
      }
    ]
  },
  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'
    }),
    new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css$/g,
      cssProcessor: require('cssnano'), //用于优化\最小化 CSS 的 CSS处理器,默认为 cssnano
      cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给 cssProcessor 的选项,默认为{}
      canPrint: true //布尔值,指示插件是否可以将消息打印到控制台,默认为 true
    })
  ]
}

Позиция загрузчика в массиве module.rules.use. По правилам вебпака:Последний загрузчик выполняется первым, если писать сверху вниз, то первым будет выполняться нижний, если писать слева направо, то правый будет выполняться первым..

['style-loader', 'css-loader', 'sass-loader']

Порядок выполнения такойsass-loader --> css-loader --> style-loader

Сначала вы должны использовать sass-loader для компиляции scss в css., остальная часть конфигурации аналогична обработке файлов css.

После упаковки и открытия файла index.html вы обнаружите, что стиль был перезаписан стилем, прописанным в main.scss, и обработка scss прошла успешно.

(4) Добавить префикс браузера в CSS

Установитьpostcss-loaderа такжеautoprefixerполагаться

npm install postcss-loader autoprefixer --save-dev

Датьsrc/scss/main.cssдобавьте этот код в

.example {
  display: grid;
  transition: all 0.5s;
  user-select: none;
  background: linear-gradient(to bottom, white, black);
}

Есть два способа настройкиpostcss, первый прописан прямо в webpack.config.js

module: {
  rules: [
    {
      test: /\.(sa|sc|c)ss$/, // 针对 .sass .scss 或者 .css 后缀的文件设置 loader
      use: [
        {
          loader: MiniCssExtractPlugin.loader
        },
        'css-loader',
        // 使用 postcss 为 css 加上浏览器前缀
        {
          loader: 'postcss-loader',
          options: {
            plugins: [require('autoprefixer')]
          }
        },
        'sass-loader' // 使用 sass-loader 将 scss 转为 css
      ]
    }
  ]
}

После упаковки проверьте файл dist/app.css.

Второй способ — создать новый файл конфигурации postcss.config.js в каталоге того же уровня, что и webpack.config.js.

module.exports = {
  plugins: [require('autoprefixer')]
}

Также в webpack.config.js

module: {
  rules: [
    {
      test: /\.(sa|sc|c)ss$/, // 针对 .sass .scss 或者 .css 后缀的文件设置 loader
      use: [
        {
          loader: MiniCssExtractPlugin.loader
        },
        'css-loader',
        'postcss-loader', // 使用 postcss 为 css 加上浏览器前缀
        'sass-loader' // 使用 sass-loader 将 scss 转为 css
      ]
    }
  ]
}

Поскольку правила в модуле выполняются в обратном порядке, приведенный выше порядок выполненияsass-loader -> postcss-loader -> css-loader -> MiniCssExtractPlugin.loader

postcss-loaderИспользуется после css-loader и style-loader, но перед другими загрузчиками препроцессора, такими как sass | less | stylus-loader

Пополнить:

Используйте свойство importLoaders в css-loader

module: {
  rules: [
    {
      test: /\.(sa|sc|c)ss$/, // 针对 .sass .scss 或者 .css 后缀的文件设置 loader
      use: [
        {
          loader: MiniCssExtractPlugin.loader
        },
        {
          loader: css - loader,
          options: {
            importLoaders: 2
          }
        },
        'postcss-loader', // 使用 postcss 为 css 加上浏览器前缀
        'sass-loader' // 使用 sass-loader 将 scss 转为 css
      ]
    }
  ]
}

importLoaders: 2Он представляет собой: css, встроенный в другой css, будет выполнять два предыдущих загрузчика, то есть postcss-loader и sass-loader.

Ссылаться на:руководство по официальному веб-сайту webpack

личный блог

24 примера, чтобы начать работу и освоить "Webpack4" (2)

24 примера для начала работы и освоения "Webpack4" (3)