Путь к рефакторингу: оптимизация объема пакетов webpack (очень подробно)

Webpack

Начинать

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

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

在这里插入图片描述
Давайте еще раз взглянем на размер упаковки, там 2,75М, что уже очень много:
在这里插入图片描述
Мы используем плагин визуализации пакетов, чтобы увидеть, что упаковано, мы выполняем:

yarn add webpack-bundle-analyzer -D

Добавьте строку в плагины webpack.config.prod.js, обратите внимание, что порт можно изменить, не конфликтуйте:

new BundleAnalyzerPlugin({ analyzerPort: 8081 })

После того, как модификация будет завершена, выполните команду yarn run build, и во всплывающем окне браузера у меня будет вот так:

在这里插入图片描述
Хорошо видно, что на antd и react-dom приходится больше половины из них, давайте их оптимизируем ниже.

1. Изменить режим

Перейдем к webpack.config.prod.js:

//mode:'development'
mode:'production' //修改成生产环境

Затем проверьте размер пакета, который мгновенно уменьшается более чем вдвое.Если он будет изменен в среде разработки, webpack автоматически оптимизирует размер пакета, например, сжатие кода и тому подобное:

在这里插入图片描述
在这里插入图片描述

2. antd загружается по требованию

Выполнить на консоли:

yarn add babel-plugin-import -D

Затем перейдите в webpack.config.common.js для настройки:

            plugins:[
               	"@babel/plugin-transform-runtime",
                 ['import',{
                     libraryName:'antd',
                     libraryDirectory: 'es',
                     style:true
                 }]
             ]

Изменить в конфигурации меньше:

	{
         loader:'less-loader',
           options:{
              javascriptEnabled: true
           }
    }

Затем переходим к месту, где используется компонент antd, и модифицируем его для импорта в следующем виде:

// import Col from 'antd/lib/col';
// import Row from 'antd/lib/row';
// import "antd/dist/antd.css"; //css也去掉
import {Col,Row} from 'antd'

Затем выполните команду упаковки, чтобы стать 601 КБ:

在这里插入图片描述
在这里插入图片描述

3. mini-css-extract-plugin извлекает css

Мы используем плагин mini-css-extract-plugin для отделения css от js. Выполнить на консоли:

yarn add mini-css-extract-plugin -D

Настройте в webpack.config.prod.js:

//在顶部引入
const MiniCssExtractPlugin=require('mini-css-extract-plugin');

//在plugins里添加
new MiniCssExtractPlugin({//提取css
            filename:'css/main.css'
        }),

Таким образом, мы можем отдельно разделить css на папку css. Затем снова упакуйте:

在这里插入图片描述
在这里插入图片描述
Мы обнаружили, что пакет js стал меньше, а css был разделен, но на самом деле css имел 223 КБ.Когда мы открыли файл css, мы обнаружили, что css не был сжат.

Мы запускаем его в консоли. Первый сжимает css, а второй сжимает js. Первоначально js будет сжат в производственной среде, но использование optimise-css-assets-webpack-plugin приведет к тому, что сжатый js станет недействительным. Итак, мы нужно ввести дополнительный плагин для сжатия js:

yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D

Настраиваем в webpack.config.common.js:

//这个配置和module,plugins是同级的
optimization:{
        minimizer:[
            new UglifyJsPlugin({//压缩js
                cache:true,
                parallel:true,
                sourceMap:true
            }),
            new OptimizeCSSAssetsPlugin()//压缩css
        ]
    },

Потом идем в package, обнаруживаем, что css стал меньше:

在这里插入图片描述

4. DllPlugin и DllReferencePlugin

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

Создаем новый ==webpack.config.dll.js== в корневом каталоге, а затем настраиваем его внутри, т.к. DllPLugin находится под вебпаком, поэтому скачивать не нужно:

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

//只需要使用yarn run dll一次就行
module.exports={
    mode:'production',
    entry:{
    	//这里把react方面的东西和babel放到这里
        vendor:['react','react-dom','react-router-dom']
    },
    output:{
        filename:'dll/_dll_[name].js',
        path:path.resolve(__dirname,'dist'),
        library:'_dll_[name]'
    },
    plugins:[
        new webpack.DllPlugin({
            name:'_dll_[name]',
            path:path.resolve(__dirname,'dist/dll','mainfist.json')
        }),
        new CleanWebpackPlugin(['./dist/dll']),//删除dll目录下的文件
    ]
}

Затем перейдите к ==webpack.config.common.js== для настройки:

//在plugins下新增
new webpack.DllReferencePlugin({
     manifest: path.resolve(__dirname, 'dist/dll', 'mainfist.json')
}),

Затем перейдите в package.json для настройки:

//在scripts下面新增一条这个
"dll": "webpack --config webpack.config.dll.js"

Выполнить на консоли:

yarn run dll

在这里插入图片描述
Мы обнаружили, что он был упакован, и нам все еще нужно перейти в public/index.html для импорта:

//在body最后新增
<script src="dll/_dll_vendor.js"></script>

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

在这里插入图片描述
在这里插入图片描述
Размер файла снова стал меньше.

5. @babel/polyfill

Как мы видим на предыдущем рисунке, core-js занимает большую часть тома, который представляет собой библиотеку, используемую babel/polyfill. Здесь я предлагаю два метода.

1. @baebl/polyfill загружается по запросу

Мы можем использовать свойство useBuiltIns, новое в babel 7. Нам нужно настроить его следующим образом:

presets:[
    [
        '@babel/preset-env',
        {
            "targets": {
                "browsers": [
                    "ie >=9",
                    "last 2 version",
                    "> 5%",
                    "not dead"
                ]
            },
            "useBuiltIns":"usage"
        }
    ],
    '@babel/preset-react'
],

Когда мы настроим это так, мы можем поставить вершину index.js

//import '@babel/polyfill'  //可以去掉这一行了

Затем мы снова упаковываем и выполняем сборку запуска пряжи:

在这里插入图片描述
在这里插入图片描述
В это время размер пакета стал 132kb, но когда я использую этот метод, он может нормально отображаться под ie11, а в ie10 и ниже возникает следующая ошибка:
在这里插入图片描述
Я еще не нашел решение, пожалуйста, дайте мне знать, если у вас есть решение, спасибо. Вы можете использовать этот метод, если вам не нужна совместимость с ie10 или ниже.

2. Извлеките @baebl/polyfill

Второй метод, мы можем напрямую извлечь @babel/polyfill, как ведро семейства React. Заходим в ==webpack.config.dll.js== для настройки:

//添加@babel/polyfill
vendor:['react','react-dom','react-router-dom','@babel/polyfill']

Затем перейдите в начало index.js и добавьте:

import '@babel/polyfill'

Затем переходим к выполнению yarn run dll, и видим, что пакет вендора стал больше:

在这里插入图片描述
Затем мы выполняем сборку запуска пряжи:
在这里插入图片描述
在这里插入图片描述
Мы обнаружили, что размер пакета аналогичен предыдущему способу, и затем мы идем в ie, чтобы увидеть:
在这里插入图片描述
Эта ошибка возникает только при ==ie8==, ie9 и выше отображаются нормально, и совместимость очень хорошая, поэтому выбор между этими двумя методами зависит от того, должна ли ваш проект быть совместим с ie.

6. динамическая загрузка реактивного маршрутизатора (ленивая загрузка реактивных компонентов)

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

Выполняем в консоли:

yarn add react-loadable babel-plugin-syntax-dynamic-import -D

Как настроить в ==webpack.config.common.js==:

plugins:[
    "@babel/plugin-transform-runtime",
    'babel-plugin-syntax-dynamic-import',//增加这一行
    ['import',{
        libraryName:'antd',
        libraryDirectory: 'es',
        style:true
    }]
]

Затем переходим к месту использования маршрута и модифицируем:

import Loadable from 'react-loadable';//注意要加上这一行
// import A from '../pages/A/A'
// import B from '../pages/B/B'

//修改成这样子的写法
const A = Loadable({
    loader: () => import('../pages/A/A'),
    loading:()=> {
        return <div>Loading...</div>
    }
});
const B = Loadable({
    loader: () => import('../pages/B/B'),
    loading:()=> {
        return <div>Loading...</div>
    }
});

Затем перейдите к выполнению команды пакета, а затем проверьте:

在这里插入图片描述
在这里插入图片描述
Мы обнаружили, что размер пакета стал больше. Это потому, что я ничего не писал в проекте сейчас, поэтому после введения плагина пакет станет больше. После написания большего количества компонентов эта динамическая загрузка может уменьшить много объема.

Мы можем посмотреть на эффект:

Вот что происходит при загрузке страницы

在这里插入图片描述
После нажатия на маршрут он становится таким:
在这里插入图片描述
Вы можете видеть, что файл js загружается динамически.

Объяснение объема index.js

Давайте поговорим об упакованной карте здесь. На самом деле, я написал очень мало кода под src, но в упакованной карте есть файл index.js размером почти 90 КБ. Почему это так? На самом деле это компонент, который antd загружает и упаковывает по требованию. Мы можем попробовать его. Это код компонента antd, который я сейчас использую на большей части домашней страницы:

<div>
    <Header/>
    <Row>
        <Col xs={24} sm={24} md={6} lg={4} xl={4} xxl={4}>
            <Aside/>
        </Col>
        <Col xs={24} sm={24} md={18} lg={20} xl={20} xxl={20}>
            <div className="content">
                {this.props.children}
            </div>
        </Col>
    </Row>
</div>

Мы закомментируем все используемые нами компоненты antd, оставив только заголовок:

//import {Col,Row} from 'antd'

<div>
    <Header/>
    {/*<Row>*/}
        {/*<Col xs={24} sm={24} md={6} lg={4} xl={4} xxl={4}>*/}
            {/*<Aside/>*/}
        {/*</Col>*/}
        {/*<Col xs={24} sm={24} md={18} lg={20} xl={20} xxl={20}>*/}
            {/*<div className="content">*/}
                {/*{this.props.children}*/}
            {/*</div>*/}
        {/*</Col>*/}
    {/*</Row>*/}
</div>

Затем переходим к упаковке:

在这里插入图片描述
在这里插入图片描述
Теперь пакет под src стал очень маленьким.

7. splitChunks

Затем мы отделяем сторонние библиотеки, такие как antd, от основного пакета.

Мы настраиваем его в оптимизации в ==webpack.config.common.js==, на том же уровне, что и ==minimizer==, где мы писали js и css сжатие раньше:

splitChunks:{
    cacheGroups:{
        vendors:{//node_modules里的代码
            test:/[\\/]node_modules[\\/]/,
            chunks: "initial",
            name:'vendors', //chunks name
            priority:10, //优先级
            enforce:true 
        }
    }
}

Затем перейдите к выполнению команды упаковки:

在这里插入图片描述
在这里插入图片描述
Мы можем обнаружить, что js и css из antd были извлечены, имена чанков — это поставщики, а основной — это код, который мы написали сами, и на самом деле мы написали очень мало.

Хотя компоненты antd относительно велики, они будут упакованы только один раз, и когда сервер настроен с помощью gzip, объем может быть уменьшен более чем на треть, что все еще приемлемо.

конец

Наконец, мы оптимизировали размер основного пакета с 2,75 МБ до примерно 5 КБ, но на самом деле мы разделили большой пакет на несколько маленьких пакетов и извлекли общий код.

На самом деле есть еще один метод оптимизации с использованием внешних ресурсов, а затем с использованием CDN для импорта, но я уже использовал здесь DllPlugin, поэтому я не буду использовать этот метод, оба метода можно использовать разумно.

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

адрес гитхаба:GitHub.com/hope-Zhou/Web…

(ps: если в статье есть ошибки, укажите на них в комментариях, спасибо)