Пошаговая запись многостраничной оптимизации Vue

Vue.js

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

Разделить на несколько страниц

1. Замените одну страницу исходного проекта несколькими страницами.


здесь я добавилindex.htmlа такжеuser.htmlдве страницы.

2. Настройте vue.config.js

// vue.config.js
const titles = require('./title.js')
const glob = require('glob')
const pages = {}

glob.sync('./src/pages/**/main.js').forEach(path => {
    const chunk = path.split('./src/pages/')[1].split('/main.js')[0]
    pages[chunk] = {
        entry: path,
        template: 'public/index.html',
        title: titles[chunk],
        chunks: ['chunk-vendors', 'chunk-common', chunk]
    }
})
module.exports = {
    pages,
    chainWebpack: config => config.plugins.delete('named-chunks'),
    devServer: {
        proxy: {
            '/api': {
                target: 'http://127.0.0.1:8080',
                changeOrigin: true,
                pathRewrite: { '^/api': '' }
            }
        }
    }
}

может быть выполненvue inspectПосмотреть полную информацию о конфигурации:

Отложенная загрузка маршрута

vue-routerОфициальные примеры следующие, здесьwebpackChunkNameЕсли вы не запишете пакет, вместо него будет автоматически сгенерирован серийный номер.

//router/index.js
{
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },

Для того, чтобы облегчить отслеживание упаковки, лучше всего написать его, вы можете увидетьabout.[hash].jsувеличить размер.

Если вы хотите упаковать несколько маршрутов в один js, напишите один и тот жеwebpackChunkNameТолько что

  {
    path: '/another',
    name: 'another',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/Another.vue')
  }

после упаковкиabout.jsФайл стал больше на 0.33Кб, и на одну страницу больше.

Внедрение анализа кода BundleAnalyzerPlugin

npm i webpack-bundle-analyzerПосле изменения конфигурации vue.config.js

//vue.config.js
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;
const report = process.env.npm_config_report; 
module.exports = {
  ...
  configureWebpack: config => {
    if (report) {
      config.plugins.push(new BundleAnalyzerPlugin());
    }
  },
  ...
 }

опять такиpackage.jsonдобавлено в

  "scripts": {
    ...
    "analyze": "npm_config_report=true npm run build"
  },

Здесь, контролируяnpm_config_reportдля отображения страницы анализа выполнитеnpm run analyzeВы можете увидеть упаковку

Извлечь сторонние плагины

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

Существует два распространенных метода оптимизации: один черезcdnсоответствоватьexternalsДля достижения второго через отдельную упаковку и соответствиеDllReferencePlugin.

Если коротко, то плюсов и минусов два:
cdn+externals: Конфигурация простая, доступ к cdn возможен во всей среде.Если случайно вызвать метод внутри запакованного файла, это может привести к повторной упаковке;
DllReferencePlugin: Конфигурация более сложная, и dll нужно генерить вручную.Все точки доступа к одной и той же dll, что не вызовет повторной упаковки.

Оптимизация с помощью «внешних»

1. Простой способ настройки

Самый простой способ сделать это — вручную добавить cdn вindex.htmlсередина

<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/vue-router/3.1.3/vue-router.min.js"></script>
    <script src="https://cdn.bootcss.com/vuex/3.1.1/vuex.min.js"></script>
</body>

затем вvue.config.jsобъяснил вexternalsпункт

 configureWebpack: (config) => {
            config.externals = {
                vue: 'Vue',
                vuex: 'Vuex',
                'vue-router': 'VueRouter',
                // 'alias-name': 'ObjName'
                // 写法: 中划线: 上驼峰
            }
},

На данный момент эти зависимости больше не упакованы.

2. Различайте среду разработки и формальную среду

После того, как вышеуказанный метод настроен, потому что введениеvue.min.js, приведет кVue DevToolНе могу использовать, что делать?

const isProduction = process.env.NODE_ENV === "production";

...
configureWebpack: (config) => {
        if(isProduction){
               config.externals = {
                vue: 'Vue',
                vuex: 'Vuex',
                'vue-router': 'VueRouter',
                // 'alias-name': 'ObjName'
                // 写法: 中划线: 上驼峰
            }
        }
},

Используйте только в формальной средеexternalsМогу я? Да, но сообщается об ошибке:

Uncaught TypeError: Cannot redefine property: $router

Потому чтоindex.htmlбыл введен один раз вvue-router, если не поставитьexternals, определение будет повторяться.

Поэтому нам нужно только внедрить cdn в официальную среду и подкорректировать предыдущий код:

// vue.config.js
const cdn = {
    css: [],
    js: [
        'https://cdn.bootcss.com/vue/2.6.10/vue.min.js',
        'https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js',
        'https://cdn.bootcss.com/vuex/3.1.1/vuex.min.js',
    ],
}

module.exports={
    ...
    chainWebpack: (config) => {
        if (isProduction) {
          // 生产环境注入cdn + 多页面
          glob.sync("./src/pages/**/main.js").forEach(path => {
            const chunk = path.split("./src/pages/")[1].split("/main.js")[0];
            config.plugin("html-" + chunk).tap(args => {
              args[0].cdn = cdn;
              return args;
            });
          });
        }
    },
}

На этом шаге в многостраничном режиме есть яма, упоминает официальный представитель, ноПредложениеВозьми - будет не одинhtml-webpack-pluginэкземпляр, в то время какconfig.plugin()должны получать точныеpluginИмя, если вы стиснете зубы и будете следовать онлайн-учебнику, вы обязательно застрянете здесь. Это на самом деле довольно просто, покаvue inspect --pluginsты можешь видеть

Следующий,index.htmlПосле обработки параметров cdn все готово😝

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
    <!-- 使用CDN的CSS文件 -->
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
    <% } %>
    <!-- 使用CDN的JS文件 -->
    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.js[i] %>" rel="preload" as="script" />
    <% } %>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but vue-multiple-pages-demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>

    <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
    <% } %>

    <!-- built files will be auto injected -->
  </body>
</html>

Оптимизация с помощью `dllPlugin`

упомянутое ранее также может быть использованоdllPluginоптимизировать, но если вы используетеchromeизVue DevTool,vueне могу вставитьdllPlugin.

1. Создатьwebpack.dll.conf.js

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

// dll文件存放的目录
const dllPath = 'public/vendor'

module.exports = {
    entry: {
        core: ['vue-router','vuex'],
        // other: [],
    },
    output: {
        path: path.join(__dirname, dllPath),
        filename: '[name].dll.js',
        // vendor.dll.js中暴露出的全局变量名
        // 保持与 webpack.DllPlugin 中名称一致
        library: '[name]_[hash]',
    },
    plugins: [
        // 清除之前的dll文件
        // "clean-webpack-plugin": "^1.0.0"  注意版本不同的写法不同
        // new CleanWebpackPlugin(['*.*'], {
        //     root: path.join(__dirname, dllPath),
        // }),
        // "clean-webpack-plugin": "^3.0.0"
        new CleanWebpackPlugin(),
        // 设置环境变量
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: 'production',
            },
        }),
        // manifest.json 描述动态链接库包含了哪些内容
        new webpack.DllPlugin({
            path: path.join(__dirname, dllPath, '[name]-manifest.json'),
            // 保持与 output.library 中名称一致
            name: '[name]_[hash]',
            context: process.cwd(),
        }),
    ],
}

2. Предварительно скомпилировать dll
существуетpackage.jsonдобавлено в

script:{
    ...
    "dll": "webpack -p --progress --config ./webpack.dll.conf.js"
}

бегатьnpm run dllты сможешьpublic/vendorDLL генерируется под.

3. ВwebpackОбъявите предварительно скомпилированный раздел в
после объявленияwebpackЭти DLL пропускаются при упаковке.

// vue.config.js

  configureWebpack: config => {
    if (isProduction) {
      config.externals = {
        vue: "Vue"
        // vuex: "Vuex", 这些都改成dllPlugin编译
        // "vue-router": "VueRouter"
        // 'alias-name': 'ObjName'
        // 写法: 中划线: 上驼峰
      };
    }
    config.plugins.push(
        // 名称要和之前的一致,可以继续扩展多个
      ...["core"].map(name => {
        return new webpack.DllReferencePlugin({
          context: process.cwd(),
          manifest: require(`./public/vendor/${name}-manifest.json`)
        });
      })
    );
  },

4. Справочная DLL
Наконец, введениеindex.html, вы можете просто написать напрямую:

    <script src=./vendor/core.dll.js></script>

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

const AddAssetHtmlPlugin = require("add-asset-html-webpack-plugin");

    config.plugins.push(
    ...
      // 将 dll 注入到 生成的 html 模板中
      new AddAssetHtmlPlugin({
        // dll文件位置
        filepath: path.resolve(__dirname, "./public/vendor/*.js"),
        // dll 引用路径
        publicPath: "./vendor",
        // dll最终输出的目录
        outputPath: "./vendor"
      })
    );
  },

Готово!

наконец

DEMO

адрес:GitHub.com/Vita2333/vu…

КаждыйcommitВ соответствии с этапом конфигурации,vueиспользоватьexternalПредставлены, различая среды разработки и настройки, другиеvue-routerи т.д. используютсяdllPluginПредставлено, нуждающиеся друзья могут пойти и посмотреть :)

Ссылаться на

GitHub.com/PL или жесть US/V…
nuggets.capable/post/684490…
blog.CSDN.net/neo VE ee/art…