Оптимизация Webpack всегда заставит вас полюбить

JavaScript Webpack
Оптимизация Webpack всегда заставит вас полюбить

Ну давай же

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

Вместо того, чтобы скучать дома, учись спокойно

Во время эпидемии, несмотря ни на что, менталитет не должен рухнуть, Ухань, давай, давай, Китай

Без лишних слов, давайте начнем учиться вместе

Оптимизация - хорошее слово

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

Конечно, webpack оптимизирует тысячи раз, но я думаю, что и этого достаточно.

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

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

Есть тысячи плагинов, первый шаг установки:

  • Установить:npm i purgecss-webpack-plugin glob -D

1. Удалите бесполезные стили

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

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

Ну не бред, исправляем, начинаем настраивать

// webpack.config.js文件

const path = require('path');
// html模板
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 从js中抽离出css
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 去除无用的样式
const glob = require('glob');
const PurgecssWebpackPlugin = require('purgecss-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve('dist')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader'
                }
            },
            {   
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            }
        ]
    },
    plugins: [
        new HtmlWebpaclPlugin({
            template: './src/index.html'
        }),
        new MiniCssExtractPlugin(),
        // 去除无用的样式
        new PurgecssWebpackPlugin({
            paths: glob.sync('./src/**/*', {nodir: true})
        })
    ]
};

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

Кратко разберем и проанализируем:

  • glob используется для поиска файлов
glob.sync('./src/**/*', {nodir: true}
// 同步查找src目录下的任意文件夹下的任意文件
// 返回一个数组,如['真实路径/src/css/style.css','真实路径/src/index.js',...]
// {nodir: true}表示不包含文件夹,加快查找速度
  • purgecss-webpack-plugin для удаления бесполезного css
new PurgecssWebpackPlugin({
    // paths表示指定要去解析的文件名数组路径
    // Purgecss会去解析这些文件然后把无用的样式移除
    paths: glob.sync('./src/**/*', {nodir: true})
})

Готово, переходите по следующей ссылке! ! !

2. динамически добавить CDN

Вставьте файл cdn в файл html и настройте его в веб-пакете.externals, чтобы библиотека импортируемого cdn не была запакована

// index.html文件

<body>
    <div id="root"></div>
    <!-- 引入jquery的cdn -->
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</body>

// webpack.config.js文件

module.exports = {
    externals: {
        'jquery': '$'
    }   
}

После написания этого мы можем использовать оператор $ прямо в файле js без импорта jquery.

Но, это всего лишь переход, главный герой появится внизу

Так как каждый раз нужно вручную вводить нужный файл cdn в шаблон index.html, а потом настраивать его в webpack, это немного громоздко

Так,html-webpack-externals-pluginПоявился такой плагин

Я пропущу этапы установки и посмотрю непосредственно на код

// webpack.config.js文件

// 动态添加CDN
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');

module.exports = {
    plugins: [
        new HtmlWebpackExternalsPlugin({
            externals: [
                {   // 引入的模块
                    module: 'jquery',
                    // cdn的地址
                    entry: 'https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js',
                    // 挂载到了window上的名称
                    // window.jQuery就可以全局使用
                    global: 'jQuery'
                },
                {
                    module: 'vue',
                    entry: 'https://cdn.bootcss.com/vue/2.6.10/vue.min.js',
                    global: 'Vue'
                }
            ]
        })
    ]
};

3. Tree-shaking

Это встроенная возможность оптимизации веб-пакета, веб-пакет очень хороший и мощный, ха-ха

В производственной среде Tree-shaking будет иметь местоавтоматическое удалениеоперация

Если прошел ES6ссылка на импортпуть поставитУдалить неиспользуемый код

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

Далее давайте посмотрим на каштан:

Создайте новый common.js в каталоге src, а затем напишите в нем что-нибудь

// src/common.js文件

export const flatten = arr => {
    console.log('my-flatten');
    return arr.reduce((all, cur) => {
        if (Array.isArray(cur) {
            return [...all, ...flatten(cur)];
        } else {
            return [...all, cur];
        }
    }, []);
};

export const myBind = (fn, context) => {
    console.log('my-bind');
    let args = [].slice.call(arguments, 2);
    return function() {
        let newArgs = [].slice.call(arguments);
        fn.apply(context, args.concat(newArgs));
    }
};

ссылка на импорт

// index.js文件

import { flatten } from './common';

let arr = [1,[3,[4, 5]], [2, [20]]];
console.log(flatten(arr));

Поскольку он работает только в производственной среде, вы можете проверить его в файле dist.console.log('my-bind'), что означает, что код, на который нет ссылок, был полностью удален.

совершенный, совершенный, совершенный

Радоваться рано, это лекарство трехкратно ядовито и имеет побочные эффекты.

побочный эффект

Теперь давайте создадим еще один файл test.js в каталоге src, чтобы вы снова могли ощутить побочные эффекты.

// src/test.js文件

export default test = () => {
    console.log('test');
}

test();

На этом этапе просто измените index.js

// index.js文件

import { flatten } from './common';
import test from './test';

let arr = [1,[3,[4, 5]], [2, [20]]];
console.log(flatten(arr));

Хотя тест введен, но не используется, пакетный файл bundle.js изменился, смотрите на большом экране

Как вы можете себе представить,побочный эффектПоявился, заходим в директорию dist и смотрим содержимое bundle.js, и находим код для печати тестового поля.

Что делать? Без кавычек, но упакованный, давайте отметим файл как свободный от побочных эффектов

устранить побочные эффекты

нужно сотрудничатьpackage.jsonфайл, добавьтеСвойство sideEffects, назначенный какfalseПросто избавься от этих побочных эффектов и больше не будешь их паковать, так просто

// package.json文件
{
    ...省略
    "sideEffects": false
}

Однако похоже, что упакованного css-файла я не видел, а на предыдущем снимке экрана было запаковано три файла, включая main.css.

Куда пропал CSS?

Это легко понять, потому что мы вводим css-файлы в js какimport './style.css'Таким образом, есть побочные эффекты,цитируется, но не используетсясмущение

и потому, чтоsideEffects: falseВсе метки отфильтрованы

Теперь измените значение sideEffects и дайте ему побочный эффект для удаленияОбъем

// package.json文件

{
    ...省略
    "sideEffects": ["./src/**/*.css"]
}

Отфильтруйте побочные эффекты импортированного файла CSS, чтобы можно было снова найти потерянный файл CSS.

На этом встроенная Tree-shaking webpack закончена. Разве это не интересно? Webpack — хорошая практика.

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

4. Динамическая библиотека DllPlugin

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

Поэтому существует подключаемый модуль под названием DllPlugin, который полностью встроен в webpack, поэтому вы можете уверенно его использовать.

эффект:

  • При упаковке в первый раз упакуйте среду разработки, используемую для упаковки напрямую, а затем создайте файл manifest.json.
  • При упаковке снова, пока естьimport React from 'react'Для такой ссылки он сначала обратится к так называемому файлу кеша, чтобы найти его, и использовать его напрямую, когда он его найдет, без необходимости снова упаковывать реакцию.
  • Конечно, если не найдёте, не помешает перепаковать фреймворк.

Я слишком много сказал, это все слезы, посмотрите на код более реалистично, перепишите index.js

// index.js文件

import React from 'react';
import { render } from 'react-dom';
import './style.css';

render(<React.Fragment>
    <h1 className="title">听妈妈的话-周杰伦</h1>
    <button className="btn">显示歌词</button>
</React.Fragment>, window.root);

Переписав index.js, давайте упакуем его с помощью npm run build.

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

Итак, давайте посмотрим, как DllPlugin поможет нам с этим справиться.

Создайте библиотеку динамических ссылок

существуетКорневая директорияЗатем создайте файл webpack.dll.js, чтобы упаковать файл dll.

// webpack.dll.js文件

const path = require('path');
// 引入webpack
const webpack = require('webpack');

module.exports = {
    entry: ['react', 'react-dom'],
    output: {
        filename: 'react.dll.js',
        path: path.resolve('dll'),
        library: 'react'    // 打包后被引用的变量名
    },
    plugins: [
        // 动态链接库
        new webpack.DllPlugin({
            name: 'react',
            path: path.resolve('dll', 'manifest.json')
        })
    ]
};

Код закончен,npm run dll, то появится папка dll, в которой будут файлы, которые вы запаковали, как показано ниже

После того, как упаковка завершена, наша очередь процитировать момент

Справочная библиотека динамических ссылок

Вернемся к нашему основному полю боя webpack.config.js

// webpack.config.js文件

const path = require('path');
// 引入webpack
const webpack = require('webpack');

module.exports = {
    plugins: [
        // 引用对应的动态链接库的manifest.json文件
        // 这样以后再引入react的时候就会优先在json文件里去寻找
        new webpack.DllReferencePlugin({
            manifest: path.resolve('dll', 'manifest.json')
        })
    ]
};

Здесь не дописано, оно еще должно быть в директории srcindex.htmlВнесите его в шаблон

<script src="../dll/react.dll.js"></script>

вставить предложение: Причина, по которой создается новый каталог dll, заключается в том, что при компиляции среды разработки npm run dev все содержимое каталога dist находится в памяти, и файл react.dll.js не может быть найден.

Хорошо, теперь давайте посмотрим на эффект, npm run dev запустите его.

Конечно, некоторые люди могут спросить, а что, если нужно импортировать больше файлов?

В конце концов, ручное введение в index.html — это не долгосрочное решение, так что давайте посмотрим на хорошую вещь дальше.

Динамически импортировать js

пройти черезadd-asset-html-webpack-pluginПлагин может выполнить такие требования, см. код

// webpack.config.js文件

const webpack = require('webpack');
// 添加资源到html文件
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
    plugins: [
        // 引用打包好的react,不会打包到bundle里
        new webpack.DllReferencePlugin({
            manifest: path.resolve('dll', 'manifest.json')
        }),
        // 直接将打包好的react.dll.js添加到html模板
        new AddAssetHtmlWebpackPlugin({
            filepath: path.resolve('dll', 'react.dll.js')
        })
    ]
};

После вышеуказанного преобразования файл react.dll.js динамически добавляется в html-файл.

Мы можем вручную ввести строку js в шаблон index.html ранее.удалятьПотерянный

5. Ленивая загрузка

Когда дело доходит до отложенной загрузки, это должно быть хорошим способом оптимизации веб-страниц или приложений, тогда ES6 также используется в веб-пакете.import() синтаксис для введения.

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

Студенты, которые использовали Vue-Router, знают, что маршруты, написанные всеми, проходят черезcomponent: () => import()Кстати, он также может быть лениво загружен

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

// index.js文件

import './style.css';
import React from 'react';
import { render } from 'react-dom';

// 写个辅助的类
class Music extends React.Component {
    constructor() {
        super();
        this.state = { lrc: [] };
    }
    showLrc() {
        // 通过ES6的import()方法实现了懒加载功能,实际上是利用了jsonp去动态导入了
        import('./lrc').then(data => {
            let lrc = data.default.split('\n').filter(item => item !== '');
            this.setState({ lrc });
        });
    }
    render() {
        return (
            <div>
                <button className="btn" onClick={() => this.showLrc()}>显示歌词</button>
                <div className="lrc-box">
                    {this.state.lrc && this.state.lrc.map((item, index) => (
                        <p className="lrc" key={index}>{item}</p>
                    ))}
                </div>
            </div>      
        )
    }
}

render(<React.Fragment>
    <h1 className="title">听妈妈的话-周杰伦</h1>
    <Music></Music>
</React.Fragment>, window.root);

npm run devДавайте посмотрим, есть ли эффект ленивой загрузки.

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

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

Далее, давайте перейдем к оптимизации, о которой часто говорят, пожалуйста, продолжайте читать, не останавливайтесь

6. Извлеките общедоступный код

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

Вот каштан, например, там два файла js, один index.js, а другой lrc.js, оба ссылаются на известную библиотеку утилит lodash, код такой

// index.js文件

import _ from 'lodash';
console.log(_.xor([2, 1], [2, 3]));


// lrc.js文件
import _ from 'lodash';
console.log(_.flatten([1,[3, 4, 5, [2]]]));

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

Итак, лодаш должен бытьизвлечен, не много ерунды, смотрите на прикол

Извлечь сторонние модули

// webpack.config.js文件

module.exports = {
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    chunks: 'initial',
                    minSize: 0,
                    minChunks: 2,
                    test: /node_modules/,
                    priority: 1
                }
            }
        }
    }
};

Webpack4 поставляется с методом извлечения общего кода черезoptimizationsplitКнопки в

Есть два преимущества извлечения сторонних модулей.

  • Не упакован с бизнес-логикой
  • Увеличить кеш 304

Извлечь общие модули

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

// index.js文件
import { flatten } from './common';
console.log('index',flatten([1,[33, 4, 5, [34]]]));

// lrc.js文件
import {flatten} from './common';
console.log(flatten([1,[33, 4, 5, [34]]]));

Метод flatten, написанный на common.js, представлен в двух js-файлах выше, поскольку все они ссылаются на common.js, его, конечно, можно извлечь.

Затем обратитесь к реализации извлечения стороннего кода для его написания.

// webpack.config.js文件

module.exports = {
    optimization: {
        splitChunks: {
            cacheGroups: {
                utils: {
                    chunks: 'initial',
                    minSize: 0,
                    minChunks: 2
                }
            }
        }
    }
};

Вышеизложенное предназначено для извлечения общедоступной части кода, пока

7. Горячее обновление

Можно сказать, что горячее обновление очень эффективно для разработки, и у webpack теперь есть собственный плагин для поддержки горячего обновления.

пройти черезdevServerзапустить горячее обновление

☆: Использование devServer необходимо установить заранее в проектеwebpack-dev-server

Итак, давайте сначала взглянем на часть конфигурации:

// webpack.config.js文件

// 引入webpack
const webpack = require('webpack');

module.exports = {
    devServer: {
        hot: true,  // 启动热更新
        port: 8080,
        contentBase: './dist'
    },
    plugins: [
        // webpack支持热更新插件
        new webpack.HotModuleReplacementPlugin(),
        // 打印更新了的文件路径
        new webpack.NamedModulesPlugin()
    ]
};

Горячие обновления доступны только всреда разработкиСпуститесь и сделайте это, поэтому после настройки выполните npm run dev

Теперь вернемся к файлу index.js и прочувствуем его.

// index.js文件


// 热更新
// 在src目录下新创建了audio.js文件
// 需要导入这个文件,不然热更新失效
import audio from './audio';

// 检查是否支持热更新
if (module.hot) {
    // 接收热更新的模块
    module.hot.accept('./audio.js', (path) => {
        console.log(path);
        console.log('audio文件更新了');
    });
}

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

Горячее обновление теперь является старым другом в разработке.Многие IDE настроены на операции горячего обновления, такие как компиляторы, такие как Android Studio, которые ускоряют компиляцию посредством горячего обновления.

Ладно, давайте замолчим, дальше еще полно галантерейных товаров, наслаждайтесь.

8. Запрос между источниками

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

или через старых друзейdevServerДля достижения приведенный выше код

  1. Первый междоменный метод
// webpack.config.js文件

module.exports = {
    devServer: {
        proxy: {
            // 可以这样写
            // '/api': 'http://localhost:3000',
            // 也可以这样写,多配置
            '/api': {
                target: 'http://localhost:3000',
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }
};

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

  • target
    • Укажите URL-адрес для запроса междоменного
    • Например, если вы запросите /api/userInfo, он будет проксирован на http://localhost:3000/api/userInfo.
  • pathRewrite
    • Как следует из названия, перепишите путь
    • Не все интерфейсы начинаются с /api, поэтому, если вы встретите интерфейс, это /getSongs.
    • Вместо адреса интерфейса /api/getSongs он перепишет /api в нулевые символы.
    • Наконец, вы можете посетить http://localhost:3000/getSongs.
  1. Второй междоменный метод
// webpack.config.js文件

module.exports = {
    devServer: {
        // 利用node来写
        before(app) {
            // 相当于直接写了后端的接口,哈哈
            app.get('/api/info', (req, res) => {
                res.json({
                    nickname: '我滴个大榴莲啊',
                    level: 8,
                    src: 'https://music.163.com/song/media/outer/url?id=1382794914.mp3'
                });
            });
        }
    }
};

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

9. IgnorePlugin

эффект:игнорировать упаковкуКаталог, указанный сторонним модулем

Зачем игнорировать это? Взгляните на каштаны ниже

Я думаю, что многие слышали о библиотеке моментов времени более или менее, не важно, если вы не знаете, я продемонстрирую это.

Сначала установите момент:npm i moment -S

// index.js文件

// 导入moment
import moment from 'moment';

// 设置中文
moment.locale('zh-cn');
let time = moment().endOf('day').fromNow();

window.root.innerHTML += time;

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

Это причина Shenma. На самом деле, когда момент импортируется, он поставляется со всем языковым пакетом локали. Такое поведение «купи один-получи один бесплатно» не нужно упоминать в мире кода, и это невыносимо.

Нам нужно использовать китайский пакет, но мы не хотим упаковывать все языковые пакеты, поэтому пусть выйдет IgnorePlugin

// webpack.config.js文件

const webpack = require('webpack');

module.exports = {
    plugins: [
        // 忽略moment目录下的locale文件夹
        new webpack.IgnorePlugin(/\.\/locale/, /moment/)
    ]
};

После перезаписи конфигурации вернитесь к index.js и отдельно импортируйте китайский языковой пакет.

// index.js文件

// 利用IgnorePlugin把只需要的语言包导入使用就可以了,省去了一下子打包整个语言包
import moment from 'moment';
// 单独导入中文语言包
import 'moment/locale/zh-cn';

let time = moment().endOf('day').fromNow();

window.root.innerHTML += time;

опять такиnpm run buildПосле упаковки объем моментально уменьшился на 278к ах ах ах, на следующей картинке видно

10. noParse

Роль noParse не в том, чтобы анализировать используемые вами сторонние библиотеки.Библиотека зависимостей

Не говорите ерунды, сразу переходите к коду

// webpack.config.js文件

module.exports = {
    module: {
        // 不去解析jquery或lodash中的依赖库
        noParse: /jquery|lodash/,  
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    }
}

На работе игнорирование больших библиотек можетУлучшить производительность сборки, улучшение скорости видно по времени сборки, например jquery и lodash, упомянутых в приведенном выше коде.

11. resolve

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

решить общую конфигурацию

  • modules
    • Указывает расположение каталога для анализа сторонних пакетов.
  • alias
    • Укажите псевдоним импорта при импорте, упростите импорт
  • extensions
    • Автоматически анализировать определенное расширение
    • По умолчанию это будетjsа такжеjsonкак расширение
// webpack.config.js文件

const { resolve } = require('path');

module.exports = {
    resolve: {
        modules: [resolve('node_modules')],
        alias: {
            Utils: resolve(__dirname, 'src/utils/'),
            '@': resolve(__dirname, 'src')
        },
        extensions: ['.js', '.css', '.json']
    }
}

В этот момент мы создаем папку utils в каталоге src, а затем создаем новый файл parse-url.js.

// src/utils/parse-url.js文件

// 就简单导出一下
export default '我是解析url的方法';



// src/index.js文件

import parseUrl from 'Utils/parse-url';

console.log(parseUrl); // 打印:我是解析url的方法

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

12. включить и исключить

  • include: включить синтаксический анализ файлов в указанном каталоге
  • exclude: исключить указанный каталог из разбора

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

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader'
                },
                exculde: /node_modules/,    // 二选一
                include: path.resolve('src')    // 二选一
            }
        ]
    }
}

13. happypack

WebPack работает в среде узла, поэтому это однопоточная работа, одна часть будет работать. Это не приятно, в случае сейчас ЦП настолько могучий, используя многоядерные операции, полностью педиатрия

Итак, место для хэппипака есть, его роль заключается в достиженииМультипроцессная упаковкадействовать

Давайте посмотрим, как настроить

Установите его перед настройкойnpm i happypack -D

// webpack.config.js文件

const Happypack = require('happypack');

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                use: 'Happypack/loader?id=js'
            },
            {
                test: /\.css$/,
                use: 'Happypack/loader?id=css'
            }
        ]
    },
    plugins: [
        new Happypack({
            id: 'js',
            use: [
                {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            '@babel/preset-env',
                            '@babel/preset-react'
                        ]
                    }
                }
            ]
        }),
        new Happypack({
            id: 'css',
            use: ['style-loader', 'css-loader']
        })
    ]
}

Почти все очень тяжело, ха-ха, настаивая на маленьких партнерах, которые смотрят вниз, это слишком сильно.

Простое предложение

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

Эпидемия опять пройдет, бояться нечего, давайте работать вместе! ! !

Спасибо всем, 886