Обобщить несколько методов оптимизации упаковки веб-пакетов.

Webpack
Обобщить несколько методов оптимизации упаковки веб-пакетов.

Зачем оптимизировать упаковку?

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

Наша цель

  • Уменьшен размер файла после упаковки
  • Главная Импорт файлов по запросу
  • Оптимизация времени связывания веб-пакетов

Метод оптимизации

1. Загрузка по требованию

1.1 Компоненты маршрутизации загружаются по запросу

const router = [
  {
    path: '/index',
    component: resolve => require.ensure([], () => resolve(require('@/components/index')))
  },
  {
    path: '/about',
    component: resolve => require.ensure([], () => resolve(require('@/components/about')))
  }
]

1.2 Компоненты и плагины третьих сторон. Загрузка по требованию требует внедрения сторонних компонентов

// 引入全部组件
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)

// 按需引入组件
import { Button } from 'element-ui'
Vue.component(Button.name, Button)

1.3 Для некоторых плагинов, если они используются только в отдельных компонентах, можно также не вводить их в main.js, а вводить в компоненты по мере необходимости

// 在main.js引入
import Vue from vue
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)

// 按组件按需引入
import { Vuelidate } from 'vuelidate'

2. Оптимизировать конфигурацию загрузчика

  • Оптимизируйте регулярное сопоставление
  • Включите кеширование с помощью параметра cacheDirectory.
  • Уменьшите количество обрабатываемых файлов с помощью включения и исключения.
module: {
  rules: [
    {
      test: /\.js$/,
      loader: 'babel-loader?cacheDirectory',
      include: [resolve('src')]
    }
  ]
}

3. Оптимизируйте пути к файлам — сэкономьте время на поиске файлов

  • После того, как расширение настроено, вам не нужно добавлять расширение файла при запросе или импорте, он попытается добавить расширение, в свою очередь, для соответствия.
  • После того, как mainFiles настроен, вам не нужно добавлять имя файла, он по очереди попытается сопоставить добавленное имя файла.
  • alias может ускорить поиск модулей Webpack, настроив псевдонимы.
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },

4, производство закрыто

  • sourceMap — это, по сути, отношение сопоставления. Код в упакованном файле js можно сопоставить с определенным расположением файла кода. Это отношение сопоставления поможет нам напрямую находить ошибки в исходном коде.
  • Скорость упаковки замедляется, а производственный файл становится больше, поэтому среда разработки использует sourceMap, а производственная среда закрывается.

5. Сжатие кода

  • UglifyJS: метод сжатия кода по умолчанию, используемый vue-cli, он использует однопоточный код сжатия, а время упаковки медленное.
  • ParallelUglifyPlugin: откройте несколько подпроцессов и назначьте работу по сжатию нескольких файлов нескольким подпроцессам для завершения.

Оба метода используются следующим образом:

plugins: [
  new UglifyJsPlugin({
    uglifyOptions: {
      compress: {
        warnings: false
      }
    },
    sourceMap: true,
    parallel: true
  }),

  new ParallelUglifyPlugin({
    //缓存压缩后的结果,下次遇到一样的输入时直接从缓存中获取压缩后的结果并返回,
    //cacheDir 用于配置缓存存放的目录路径。
    cacheDir: '.cache/',
    sourceMap: true,
    uglifyJS: {
      output: {
        comments: false
      },
      compress: {
        warnings: false
      }
    }
  })
]

Сравнение скорости упаковки и размера файла после упаковки

метод Размер файла Скорость упаковки
без плагинов 14.6M 32s
UglifyJsPlugin 12.9M 33s
ParallelUglifyPlugi 7.98M 17s

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

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

webpack3 использует реализацию CommonsChunkPlugin:

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    minChunks: function(module, count) {
      console.log(module.resource, `引用次数${count}`)
      //"有正在处理文件" + "这个文件是 .js 后缀" + "这个文件是在 node_modules 中"
      return module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, './node_modules')) === 0
    }
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'common',
    chunks: 'initial',
    minChunks: 2
  })
]

реализация webpack4 с использованием splitChunks:

module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          priority: 1, //添加权重
          test: /node_modules/, //把这个目录下符合下面几个条件的库抽离出来
          chunks: 'initial', //刚开始就要抽离
          minChunks: 2 //重复2次使用的时候需要抽离出来
        },
        common: {
          //公共的模块
          chunks: 'initial',
          minChunks: 2
        }
      }
    }
  }
}

7. Оптимизация CDN

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

1. Измените пять библиотек vue, vue-router, vuex, element-ui и axios, чтобы получить их через ссылки CDN, и вставьте соответствующие ссылки в index.html.

<head>
  <link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.0.7/theme-chalk/index.css" />
</head>
<body>
  <div id="app"></div>
  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
  <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
  <script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js"></script>
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script>
  <script src="https://cdn.bootcss.com/element-ui/2.6.1/index.js"></script>
  <!-- built files will be auto injected -->
</body>

2. В конфигурационном файле webpack.config.js

module.exports = {
 ···
    externals: {
      'vue': 'Vue',
      'vuex': 'Vuex',
      'vue-router': 'VueRouter',
      'element-ui': 'ELEMENT',
      'Axios':'axios'
    }
  },

3. Удалите зависимый пакет npm, npm uninstall axios element-ui vue vue-router vuex

4. Измените предыдущий метод импорта пакета в файле main.js.

// import Vue from 'vue'
// import ElementUI from 'element-ui'
// import 'element-ui/lib/theme-chalk/index.css'
// import VueRouter from 'vue-router'

import App from './App.vue'
import routes from './router'
import utils from './utils/Utils'

Vue.use(ELEMENT)
Vue.use(VueRouter)

const router = new VueRouter({
  mode: 'hash', //路由的模式
  routes
})

new Vue({
  router,
  el: '#app',
  render: h => h(App)
})

8. Разбирайте и обрабатывайте файлы с помощью многопроцессорного режима HappyPack.

  • Поскольку Webpack, работающий на Node.js, является однопоточной моделью, вещи, с которыми должен иметь дело Webpack, должны выполняться одна за другой и не могут выполняться одновременно.
  • HappyPack позволяет Webpack разбивать задачу на несколько подпроцессов для одновременного выполнения, а затем отправлять результат основному процессу после того, как подпроцессы его обработают.
  • HappyPack не поддерживает загрузчик файлов и URL-адресов, поэтому не рекомендуется использовать этот загрузчик.

Способ применения следующий:

  1. Установка плагина HappyPack: npm i -D happypack
  2. Файл webpack.base.conf.js настраивает module.rules.
module: {
  rules: [
    {
      test: /\.js$/,
      use: ['happypack/loader?id=babel'],
      include: [resolve('src'), resolve('test')],
      exclude: path.resolve(__dirname, 'node_modules')
    },
    {
      test: /\.vue$/,
      use: ['happypack/loader?id=vue']
    }
  ]
}
  1. Настроить в рабочей среде файл webpack.prod.conf.js
const HappyPack = require('happypack')
// 构造出共享进程池,在进程池中包含5个子进程
const HappyPackThreadPool = HappyPack.ThreadPool({ size: 5 })
plugins: [
  new HappyPack({
    // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
    id: 'babel',
    // 如何处理.js文件,用法和Loader配置中一样
    loaders: ['babel-loader?cacheDirectory'],
    threadPool: HappyPackThreadPool
  }),
  new HappyPack({
    id: 'vue', // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
    loaders: [
      {
        loader: 'vue-loader',
        options: vueLoaderConfig
      }
    ],
    threadPool: HappyPackThreadPool
  })
]

Суммировать

  1. Более практичные методы: загрузка по требованию, оптимизация конфигурации загрузчика, закрытие исходной карты производственной среды и оптимизация CDN.
  2. Оптимизация, которую сделал vue-cli: сжатие кода, извлечение общего кода, и места для оптимизации не так много.
  3. Метод оптимизации выбирается в соответствии с реальными потребностями проекта и его собственным уровнем развития, и необходимо избегать ошибок, связанных с оптимизацией.

Статьи по Теме