Разделение кода веб-пакета

внешний интерфейс JavaScript React.js Webpack

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

Фон, на котором появляется разделение кода

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

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

Как webpack реализует разделение кода

webpack достигает вышеуказанных целей тремя способами:

  1. Точки входа: несколько записей упакованы отдельно
  2. Предотвращение дублирования: удалите дублирование, извлеките общедоступные модули и сторонние библиотеки.
  3. Динамический импорт: динамическая загрузка Вместо того, чтобы подбирать определения в документе, мы будем постепенно понимать их различные функции на примере.

Предположим, у нас есть такой проект со следующими файлами

Код очень простой (просто пример, написанный непосредственно на синтаксисе commonjs):

//a.js
var react = require('react')
var tool = require('./tool')
var b = require('./b')
function load(){
    b()
    tool()
    console.log('全部文件都从一个入口打包')
}
load()
//b.js
var react = require('react')
var tool = require('./tool')
function b(){
    tool()
    console.log('这是bjs文件')
}
module.exports = b;
//tool.js
var react = require('react')
function tool(){
    console.log('这是tooljs文件')
}
module.exports = tool;

Конфигурация проста:

var webpack = require('webpack');module.exports = {
    entry: './codesplitting/c1/a.js',
    output: {
        path: __dirname,
        filename: '/dist/index.js'
    }
    //*****
}

Прямая упаковка: видно, что размер файла 2047 строк, объем тоже стал больше

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

Entry Points

Если проект в бизнесе — это не одностраничное приложение, этот шаг можно пропустить, а это уже непосредственно многовходовая упаковка. Вот для демонстрации эффекта, принудительно разделим его на модуль и запакуем.Предполагая, что наш файл тоже очень большой, нам нужно запаковать b.js отдельно:

    entry: {
        index:'./codesplitting/c1/a.js',
        other:'./codesplitting/c1/b.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name].js'
    },
    //***

Здесь также необходимо изменить a.js, чтобы удалить ссылку на b. Входные файлы не могут ссылаться друг на друга. Иначе будет большая проблема, кто главный, вот и попадете в проблему круговой ссылки. Сгенерированный файл на данный момент выглядит следующим образом:


Кажется, что файл только немного меньше, не так ли? Оптимизация первого шага выполнена здесь, очевидно, вы подумаете, что я шучу.
Конечно это только первый шаг в долгом марше.Глядя на файлы под dist, не сложно обнаружить, что сторонние библиотеки реагируют и в двух файлах вписан многоразовый модуль tool.js.Очевидно, нет необходимости повторять упаковку.
Можно ли вынуть эти многоразовые модули и упаковать их отдельно?
Таким образом, браузер кэширует файл после первого запроса, а с сервера запрашивается только уменьшенный размер бизнес-файла, поэтому скорость загрузки, очевидно, улучшится.
Если вы тоже так думаете, давайте продолжим читать вместе.

Prevent Duplication

webpack удаляет повторяющиеся ссылкиCommonsChunkPluginплагин для достижения. Элементы конфигурации плагина следующие:

{
    //被抽离为公共文件的chunk名,例如common,可以是string或者数组
    //显然如果是单个的模块,就是name多个就是names
    name:string,
    names:[],
    //打包之后公共模块的名称模板
    //例如'[name].js'
    //如果省略,则和name名称一致
    filename:string,
     //模块被引的最小次数,也就是说至少有几个组件引用了该模块。
    //如果是Infinity,则表明单纯的创建,并不做任何事情
    minChunks:2  
}

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

entry: {
        index:'./codesplitting/c1/a.js',
        other:'./codesplitting/c1/b.js',
        //第三方库显示声明
        vendor:['react'],
        //公共组件声明为common
        common:['./codesplitting/c1/tool']
    },
    //***
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            names:["common", "vendor"],
            filename: "[name].js"
        })  
    ]

Результат упаковки такой:

Видно, что индекса и других бизнес-пакетов уже очень мало, а реакт выделен в отдельный пакет.
Также существует проблема, заключающаяся в том, что некоторый код может выполняться только при определенных условиях, а может и не выполняться.
Я не хочу загружать его на первом экране, как мы часто говорим о загрузке по требованию. Давайте смотреть вместе.

Dynamic Imports

Webpack рекомендует следующие два способа использования динамической загрузки.

1), import() в ECMAScript в состоянии предложения

2), специфичный для веб-пакета require.ensure

Здесь мы используем второй, чтобы увидеть эффект (в конце концов, babel бесполезен из-за лени...), динамически внедряя di.js в js

    //虽然始终会加载,大家能明白就行
    if(true){
        require.ensure([],function(require){
            var di = require('./di')
        })
    }
    //新增动态加载的js
    function di(){
        tool()
        console.log('这是动态引入的文件')
    }
    module.exports = di;

После запуска вы можете найти больше 2.2.js, открыть его, и вы обнаружите, что это наш новый динамически представленный di.js

Вы можете спросить, как быть уверенным, что он импортируется динамически, хотя этот пример может только посмотреть пример после упаковки (dev-сервер не будет введен, все-таки ленивый...) Мы все еще можем видеть результат от код. Во-первых, посмотрите на файл index.js, вы можете увидеть следующий код:

      var react = __webpack_require__(2)
	   var tool = __webpack_require__(1)  
	   /****省略8*****/
      //虽然始终会加载
	    if(true){
	        __webpack_require__.e/* nsure */(2, function(require){
	            var di = __webpack_require__(13)
	        })
	    }

В отличие от модулей, требующих напрямую, require.ensure преобразуется вwebpack_require.e, давайте продолжим смотреть, для чего этот метод полезен.

   	__webpack_require__.e = function requireEnsure(chunkId, callback) {
		// "0" is the signal for "already loaded"
		if(installedChunks[chunkId] === 0)
			return callback.call(null, __webpack_require__);

		// an array means "currently loading".
		if(installedChunks[chunkId] !== undefined) {
			installedChunks[chunkId].push(callback);
		} else {
			// start chunk loading
			installedChunks[chunkId] = [callback];
			var head = document.getElementsByTagName('head')[0];
			var script = document.createElement('script');
			script.type = 'text/javascript';
			script.charset = 'utf-8';
			script.async = true;

			script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"common","1":"index","3":"other"}[chunkId]||chunkId) + ".js";
			head.appendChild(script);
		}
	};

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

заключительные замечания

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