Оптимизация проблемы дублирования пакетов Webpack dll

внешний интерфейс JavaScript Vue.js Webpack
Оптимизация проблемы дублирования пакетов Webpack dll

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

Оптимизировать фон

При оптимизации проекта компании в последнее время, в связи сРазмер загружаемого файла внутренней сети CDN ограничен 500 КБ., поэтому dll webpack используется для разделенной упаковки.Я разделил разделенный пакет на три части:

  • vue экологический пакет (vue,vuex,vue-router,vuex-class,vue-class-componentи другие близлежащие экологические библиотеки)
  • пакет плагина vue (vee-validate, внутренняя библиотека пользовательского интерфейса, предварительный просмотр изображений и другие библиотеки подключаемых модулей vue)
  • сторонние пакеты (axios, некоторая внутренняя статистика ошибок, отчеты, водяные знаки сотрудников и т. д. Эти сторонние библиотеки отделены от vue)

Три части имени пакета:vue.dll.js,plugin.dll.js,lib.dll.js, преимущество этого в том, что структура понятна, а самая главная причина это размер пакета декомпозиции, который уменьшен до менее чем 500К

Но после упаковки dll я с удивлением обнаружилvue.dll.jsа такжеplugin.dll.jsБудет содержать дублированный код vue dist

Ниже приведена диаграмма анализа расслоения первых двух частей.

vue.dll.js

plugin.dll.js

Вы можете видеть, что обе dll содержат vue

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

Конфигурация DLL

Поскольку WebPack поддерживает несколько входов, это, как правило, пакет DLL с несколькими входами, сначала рассмотрите конфигурацию WebPack, несколько входных порталов, поэтому могут быть

// webpack.dll.conf.js

module.exports = {
    // 其他配置先省略
        entry: {
             vue: ['vue', 'vuex', 'vue-router', ...],
             plugin: ['vee-validate', '内部UI库', ...],
             lib: ['axios', 'dayjs', ...]
        },
    plugins: [
        new webpack.DllPlugin({
            // dll.配置
        })
    ]
}

Тем не менее, файлы, упакованные таким способом, все еще имеют вышеуказанные проблемы.

В сочетании с тем, что я практиковал в своей предыдущей компанииwebpack multi compilerпуть, ссылкаwebpack multi compiler, конфигурацию вебпака я разделил на три, каждый dll пакет имеет конфигурацию вебпака, а именно

// config.js

exports.dll = [
    {
        name: 'vue',
        libs: ['vue', 'vuex', 'vue-router', 'vuex-class', 'vue-class-component']
    },
    {
        name: 'lib',
        libs: [axios', 'dayjs', '第三方库']
    },
    {
        name: 'plugin',
        libs: ['vee-validate', 'v-viewer', 'vue插件库']
    }
]
// webpack.dll.conf.js

module.exports = config.dll.map(function (vendor) {
    return {
        // 省略其他配置
        entry: {
            [vendor.name]: vendor.libs
        },
        plugins: [
            new webpack.DllPlugin({
                // dll.配置
            })
        ]
    }
})
// dll.js

const dllConfig = require('./webpack.dll.conf')

webpack(dllConfig, function (err, stats) {
    if (err) throw err
    // 处理stats相关信息
})

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

анализировать проблему

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

import Vue from 'vue'

// ...
// Vue相关操作
// Vue.prototype.$isServer等

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

Решение

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

Итак, я подумал, если plugin.dll.js зависит от vue в vue.dll.js, возможно ли сначала упаковать vue.dll.js, а затем ссылаться на vue.dll.js при упаковке plugin.dll.js Шерстяная ткань ?

Действие хуже, чем сердцебиение, попробуйте прямо сейчас и внесите следующие изменения.

// config.js

exports.dll = [
    {
        name: 'vue',
        libs: ['vue', 'vuex', 'vue-router', 'vuex-class', 'vue-class-component']
    },
    {
        name: 'lib',
        libs: [axios', 'dayjs', '第三方库']
    },
    {
        name: 'plugin',
        libs: ['vee-validate', 'v-viewer', 'vue插件库'],
        ref: 'vue'
    }
]

// webpack.dll.conf.js

// generate config
const gen = function (vendors) {
    return vendors.map(function (item) {
        const base = {
            entry: {
                [item.name]: item.libs
            },
            plugins: [
                new webpack.DllPlugin({
                    // dll配置
                })
            ]
        }
        
        if (item.ref) {
            // 重点在这
            // 在有ref的dll配置中,插入dll reference的plugin,内容是所依赖的dll包的manifest
            base.plugins.push(new webpack.DllReferencePlugin({
                // dll reference其他配置
                manifest: '所依赖的dll包的manifest文件路径'
            }))
        }
        
        return base
    })
}

// 根据是否有ref依赖项,区分base config和ref config
const [baseVendors, refVendors] = config.dll.vendors.reduce((config, v) => {
    config[v.ref ? 1 : 0].push(v)
    return config
}, [
    [],
    []
])

// 生成base config
const getConfig = function () {
    return gen(baseVendors)
}

// 生成ref config
const getRefConfig = function () {
    return gen(refVendors)
}

module.exports = {
    getConfig,
    getRefConfig
}
// dll.js

const dllConfig = require('./webpack.dll.conf')

// 因为ref config依赖于base config,所以要保证base config先打包出来
const runWebpack = function (config) {
    return new Promise(function (resolve) {
        webpack(config, function (err, stats) {
            if (err) throw err
            // ...
            resolve()
        })
    })
}

module.exports = function run () {
    runWebpack(dllConfig.getConfig())
        .then(() => runWebpack(dllConfig.getRefConfig()))
}

Целое становится следующей структурой

dll structure

Наиболее важным шагом является то, что plugin.dl.js будет ссылаться на файл манифеста vue.dll.js, так что общедоступная часть vue будет отображаться только в vue.dll.js, а диаграмма анализа пакетов после plugin.dll .js упакован следующим образом

plugin.dll.js

Хорошо видно, что в plugin.dll.js нет vue dist, а размер пакета оптимизирован✌️

Оптимизируемые элементы

Приведенная выше оптимизация на самом деле учитывает только одну зависимость, так что, если plugin.dll.js зависит как от vue.dll.js, так и от lib.dll.js? Что, если vue.dll.js в настоящее время также зависит от lib.dll.js?

Если возникает описанная выше ситуация, сначала подумайте, нужно ли разбивать пакет dll? Оправдан ли разрыв?

Затем подумайте, как думать о порядке упаковки с точки зрения порядка зависимостей и что делать, если существует циклическая зависимость?

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

Суммировать

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

Оригинальный адрес:Оптимизация проблемы дублирования пакетов Webpack dll