Модульная оптимизация Webpack

Node.js внешний интерфейс JavaScript Vue.js HTML CSS Webpack ECMAScript 6
Модульная оптимизация Webpack

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

Конечно, я считаю, что дети, разбирающиеся в истории фронтальной модульной разработки, должны были о ней слышать.IIFE,AMD,CommonJSи так далее, все они являются спецификациями, обеспечивающими модульность, покаES2015После того, как он вышел, модульность была официально включена в его стандарт. Прежде чем говорить о сегодняшней теме, давайте кратко объясним реализацию и различия нескольких вышеописанных модульных методов.webpack模块化优化Немного помощи.

IIFE

Прежде чем появились различные модульные спецификации,ES5Он не поддерживает модульную разработку, но в то время были и большие коровы, чтобы лучше избегать функций.副作用и инкапсуляции, начал ловко придумывать использованиеIIFEДля достижения модульности (Примечание: сам JS не имеет области на уровне блоков):

IIFE实现模块化

Видно, что в оригиналеES5На базе могут быть инкапсулированы некоторые логические модули, то есть простой闭包行为, чтобы предотвратить влияние внешней среды на внутренние переменные.

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

CommonJS

CommonJS规范Реализация представляет собой метод синхронной загрузки, который часто используется на стороне сервера.Его конечной целью является предоставление модульной стандартной библиотеки, аналогичной Python, Ruby и Java.

с этой целью,NodeJSПоявление также официально знаменует собойJavascript模块化编程рождение. На стороне сервера модули должны взаимодействовать с операционной системой или приложениями.NodeJS的模块系统является ссылкойCommonJS规范написано.

В спецификации указано, чтоexportsилиmodule.exports(Примечание: разница между использованием этих двух методов экспорта, заинтересованная детская обувь может посмотреть наОбъяснение API Руан Ифэн) для экспорта внешних переменных или интерфейсов черезrequire方法Импортируйте выходные данные других модулей в текущую область модуля. Непосредственно на каштаны:

CommonJS模块化规范

В это время могут быть допрошены детская обувь, затемCommonJSМожно ли его использовать на стороне клиента?

Ответ положительный. Поскольку в клиенте отсутствуют четыре переменные среды Node.js:module、exports、require、global, что делает клиент недоступнымCommonJS规范. Для этого сторонние инструменты или библиотеки (например,require1k,tiny-browser-requireи т. д.) для реализации клиентомCommonJS规范.

AMD

ввидуES5внутренний пропускIIFEРеализованная модуляризация не может быть модульной в том смысле, в каком она существует (аналогично Java, Python и т. д.), поэтому некоторые большие коровы предложилиAMD规范, он может импортировать модули асинхронно, а модули вполне могут инкапсулировать некоторые логические функции в файл, чтобы их импортировал основной процесс. вRequireJSБиблиотека очень хорошо реализованаAMD规范, непосредственно на примере:

AMD模块化规范

RequireJS APIнезащищенныйrequireа такжеdefineДва глобальных метода могут быть переданы, когда основной процесс или модуль должны зависеть от других модулей.requireа такжеdefineДва глобальных метода в первом параметре. В то же время мы можем видеть, чтоAMD规范Реализация представляет собой асинхронную загрузку модулей (несколько модулей будут загружаться параллельно при их вводе, что эффективно повышает эффективность выполнения и неблокирует загрузку страниц). Для каждого модуля вам нужно делать только то, что должен делать модуль, и связь между модулем и основным процессом эффективно уменьшается.

CMD

CMD规范Также называемое общим определением модуля, оно также реализует асинхронную загрузку модулей.SeaJS库Эту спецификацию очень легко реализовать, в основном она имеет следующие характеристики:

  • Использовать на: иAMD规范аналогично, используйтеrequireа такжеdefineдва глобальных метода, но с использованиемrequireметод, код модуля выполняется синхронно, что аналогичноCommonJS规范очень похожий;
  • Реализация:CMD规范Ядро загружается рано, выполняется лениво иAMD规范Ядро ранняя загрузка, раннее исполнение, конечноCommonJS规范Ядро — ленивая загрузка и отложенное выполнение;

должны знать о том,CMD规范использоватьrequireПричина этого метода в том, что в процессе предварительной загрузки модулей загруженные модули будут храниться в памяти, так что когда клиент выполняет основной процесс и импортирует модули по требованию, модули, хранящиеся в памяти, выполняются синхронно. (Заинтересовала детская обувь, можете прочитать эту статью -Как работает SeaJS)

я считаю,CMD规范Механизм ленивого выполнения может эффективно улучшить производительность взаимодействия со страницей, так как нет необходимости выполнять другие временно неиспользуемые модули до завершения процесса взаимодействия со страницей (конечно, это только мое личное мнение, если есть детская обувь с разными видами, Вы можете прокомментировать область. Напишите об этом, чтобы обсудить и изучить вместе. Для сравнения производительности детская обувь также может взглянуть.Сравнение AMD и CMD на github SeaJS очень интересно.). И этот механизм также для следующего я хочу упомянутьwebpack模块化优化тесно связаны.

Сразу перейти к следующемуSeaJSПроверьте каштаныCMD规范(Если вас интересует детская обувь, вы также можете посмотретьAPI SeaJS):

SeaJS实现CMD规范

UMD

UMD规范Его можно рассматривать как решение для решения кроссплатформенной загрузки модулей внешнего и внутреннего интерфейса, поддержкиAMD规范а такжеCommonJS规范. Проще говоря, он стремится использовать метод реализации, который может загружать модули, совместимые с интерфейсом и сервером.

Нечего сказать, заинтересованная детская обувь может взглянутьОфициальное представление и каштаны UMD. Следующее также использует простой каштан, чтобы оценитьUMD规范записывается как:

UMD的写法

можно увидеть,UMD规范Метод реализации заключается в том, чтобы сначала определить, поддерживать лиAMD规范, а затем определить, следует ли поддерживатьCommonJS规范, когда оба не поддерживаются, модуль определяется непосредственно в глобальном объекте

ES6 Module

из-заES5Отсутствие модульной концепции загрузки, поэтому вES6официально включает модульную загрузку в свой стандарт

ES6Средний модуль — это выходной интерфейс во время компиляции, а различные спецификации загрузки модулей, упомянутые выше, — это выходной интерфейс во время выполнения, как вы можете видеть.ES6 ModuleПроизводительность оптимизирована до определенной степени. Заинтересованная детская обувь может посмотретьВведение Руан Yifeng в модуль ES6. Возьмем ниже каштан:

ES6 Module栗子

В настоящее время клиент в основном используетES6 Moduleметод загрузки модуля для загрузки модулей и дляNodeСервер все еще постепенно приближается к этому способу загрузки модулей, но он все еще используется в большинстве случаев.CommonJS规范.

Я считаю, что после прочтения описанных выше различных реализаций загрузки модулей у вас должно сложиться определенное представление о модульности. Ну что, приступим к сегодняшней теме, вWebpackкак идти правильноApplicationОптимизирована ли модульность?

возникшие проблемы

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

|- src
|--- components
|------ message.vue      // 详细信息框组件
|------ main.vue         // 首页需要的组件  
|------ goods.vue        // 商品页面组件
|--- router
|------ index.js         // 路由文件
|--- App.vue             // 入口vue文件

Обычно мы пишем страницу так:

App.vue

入口vue文件

файл маршрутизации index.js

路由文件

Компонент домашней страницы main.vue

首页组件

Компонент страницы продукта goods.vue

商品页面组件

Компонент информации о продукте message.vue

商品信息组件

Каштан выше, введенный по URL-адресу во время выполненияlocalhost:8080/#/будет использоваться напрямуюMain.vueДомашний компонент, при вводеlocalhost:8080/#/goodsОтображение времениgoods.vueТоварный компонент, нажмите кнопку, чтобы отобразить его напрямуюmessage.vueДетальная составляющая.

На данный момент, я хотел бы спросить, вышесказанное простоSPAЕсть ли более оптимизированное решение для каштанов? Что делать, если я хочу ускорить загрузку главной страницы для лучшего взаимодействия с пользователем?

По вышеуказанным проблемам мы будем часто сталкиваться с ними, и вы также можете высказать свое мнение в области комментариев. Вот, я не продам, если это я, первое, что я думаю начать, этоWebpack, и это основной контент, который следует упомянуть сегодня:用Webpack如何更好地优化复杂程序的模块化.

Dynamic Import

В настоящее время пытаетсяstage 3сценаСинтаксис import() для предложений ECMAScript, я полагаю, что многие производители детской обуви знали или слышали об этом, так для чего же это нужно? Согласно официальному заявлению:

ECMAScript modules are completely static, import() enables dynamic loading of ECMAScript modules.

Проще говоря, текущая загрузка модуля загружается статически, а import() позволяет нам загружать соответствующий модуль по требованию. Потом приходит проблема, каштаны выше тоже подгружаются по требованию, домашняя страница нужна толькоMainКомпонент домашней страницы и страница продукта загружаются толькоgoodsа такжеmessageкомпоненты. Затем присмотритесь и посмотрите, действительно ли каштаны выше сделали это.按需加载?

Ответ нет, как я уже упоминал вышеES6 ModuleИнтерфейс выводится на этапе компиляции, поэтому когда мы используемWebpackПосле упаковки все необходимые модули будут внесены вjs文件середина. Поэтому в процессе загрузки домашней страницы необходимо загрузить всюjs文件Конечно, для того, чтобы пользователи могли испытать эффект, мы все знаем, что этоjs文件Есть также некоторые логики модулей, которые нам пока не нужно использовать, и это проблема, с которой мы будем иметь дело дальше.

import()Возникновение грамматики, рекомбинацияwebpack 4(Вы также можете выбратьwebpack 3), вышеуказанная проблема может быть решена изящно. Конечно такжеbabelтрансформация. Вот реализация обработки:

Частичная конфигурация webpack.config.js

webpack module关键配置

Затем измените файл маршрутизации следующим образом:

动态引入--路由文件

Вы можете увидеть это, когда мы снова посетимlocalhost:8080/#/, вы обнаружите, что загрузкаjs文件Он меньше, чем раньше, и самое главное, что нетGoodsКод товарной составляющей. при повторном посещенииlocalhost:8080/#/goods, он будет загружаться с сервера асинхронно0.jsфайл и измените файл, чтобы он содержалGoodsКод товарной составляющей. Видно, что не только редуцируется основной процессjsРазмер файла, ускоряющий загрузку страницы, а также асинхронную загрузку необходимых файлов модулей по запросу.

Хорошо, вот и мы, если я хочу снова оптимизировать егоGoodsв компоненте продуктаMessageКомпонент Details, поскольку он загружается только при нажатии кнопки, можем ли мы также разрешить его ленивую загрузку, пустьlocalhost:8080/#/goodsСледующая страница загружается быстрее?

Ответ да, но вам нужно использоватьVueсерединаcomponentГрамматика, без лишних слов, давайте изменим ее:

Компонент страницы продукта goods.vue

商品页动态引入信息组件

когда мы приедем сноваlocalhost:8080/#/goods, ты найдешьjs文件меньше, чем раньшеMessageПодробный информационный код компонента для ускорения процесса загрузки, и после нажатия кнопки он будет представлен динамически.1.jsфайл, который также загружается асинхронно с сервераMessageДетальная составляющая.

В это время могут возникнуть вопросы по тестированию детской обуви.MessageКогда появится компонент с подробной информацией, а затем снова нажмите кнопку, вам нужно повторноrender, разве это не требует определенной производительности? Ответ заключается в том, что будут потери, поэтому, если вы хотите оптимизировать его, что вы можете сделать? Это просто, просто используйтеVue APIнезащищенный<keep-alive>组件завернуть наш<component>Вот и все, это позволит эффективно сохранить компонент в памяти, и его можно будет прочитать прямо из памяти при следующем доступе.

В этот момент, возможно, некоторые детские туфли снова зададут вопросы, указанные выше0.jsдокументы и1.jsКакой к черту файл? Будьте терпеливы и посмотрите вниз, может быть, вы хотите сюрприз, ха-ха 🙊

Magic Comments

Почему появляется вышеуказанное0а также1, причина в том, что для динамического введенияimport()Не указывать имя модуляchunkNameчас,WebpackПо умолчанию следующие динамически импортируемые файлы именуются последовательно от 0 до n.

Однако для этих чисел 0 или n у нас нет возможности узнать динамическое введениеjs文件Какому модулю принадлежит, для этогоWebpackтакже предоставляет намMagic Comments, поэтому вы можете настроить имя модуля.

Возьмем за каштан динамический импорт вышеуказанного файла маршрутизации, он очень прост в использовании:

webpackChunkName指定模块名称

В это время изlocalhost:8080/#/доступ вlocalhost:8080/#/goods, вы обнаружите, что загрузка не0.js, ноgoods.js, что позволяет легко узнать, какие модули динамически импортируются. Конечно, если вас интересует детская обувь, вы также можете подумать об указанииMessage详细信息组件при динамическом импортеchunkName.

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

Extension

На самом деле, на мой взгляд, его можно еще оптимизировать. возьми вышеперечисленноеGoodsТоварный компонент, при нажатии кнопки, если загруженный модуль относительно большой, пользователю приходится ждать полной загрузки.message.jsФайл может отображаться только во всплывающем окне (конечно, таких случаев не так много, т.к. запакованные js файлы вообще хранятся на кдн, а запрос будет загружаться по принципу близости, что эффективно избегает этой проблемы, но мы все же можем обсудить, как можно избежать этой проблемы). По этой причине, есть ли у нас план по эффективному устранению этой задержки? Я не буду продавать здесь,Webpack 4.6, указывая на явную поддержкуprefetching and preloading, и эти две вещи способны решить проблему, с которой мы только что столкнулись.

Preload And PreFetch

PreloadПредварительно загружен,PreFetchэто модуль, который, по прогнозам, будет загружен, оба из которыхlinkсвойства под этикеткой. Интересует детская обувь, можете посмотретьОтносительно приоритета этих двух исполнений на стороне клиента

Проще говоря,PreloadприоритетHeight,а такжеPreFetchтогдаLow. Это разница между двумя:

  • preload: В основном используется для предварительной загрузки текущей страницы, собрания и основного файла.bundle.jsПараллельная загрузка и приоритетное получение могут использоваться для предварительной загрузки некоторых необходимых модулей.
  • prefetch: В основном используется для следующей операции или страницы, она будет загружена, когда браузер неактивен, с самым низким приоритетом.

Кроме того, следует отметить, что,preloadа такжеprefetchТекущий уровень поддержки существующих браузеров не так дружелюбен. В частности, вы можете посмотреть на две совместимости:Совместимость с предварительной загрузкойа такжеСовместимость с предварительной выборкой

Хоть совместимость и не такая дружная,preloadа такжеprefetchВсе они декларативные, поэтому даже если они не поддерживаются, они не повлияют ни на какие функции существующей страницы.

Видя это, считается, что каждый должен также думать об использованииprefetchОн может решить проблему ожидания с задержкой, с которой мы столкнулись выше, так как же его написать? Здесь нам также нужно использоватьWebpackизpreload-webpack-pluginПлагин, конфигурация написана следующим образом:

Частичная конфигурация webpack.config.js

prefetch使用

В это время будетWebpack 4.6+В версии модифицированные компоненты страницы продукта выглядят следующим образом:

Компонент страницы продукта goods.vue

prefetch--message组件

Как видите, просто добавьтеwebpackPrefetch: trueрекомбинация аннотацийpreload-webpack-pluginПлагины могут импортировать динамически импортируемые модулиPrefetch.

когда мы приедем сноваlocalhost:8080/#/goods, вы обнаружите, что после загрузки основного процессаjs文件а потом при простое в браузере автоматически загрузитсяmessage.js文件И вы можете увидеть его приоритетLowиз. Кроме того, мы также можем видеть, что в<head>этикетка, через<link>использование ярлыкаrel="prefetch"загрузитьmessage.js文件. В это время, если вы снова нажмете кнопку, вам больше не нужно будет ждать, пока задержка загрузится напрямую.Message组件.

Что касается визуализаций вышеописанной операции, то скриншоты делать не буду, интересующиеся детской обувью могут попробовать и убедиться в них лично, чтобы было более глубокое впечатление. Если возникнут неудобства, извиняюсь здесь 🙈

дляWebpack模块化加载优化, могут быть некоторые лучшие и лучшие решения, и вы можете делиться ими и учиться вместе в области комментариев. Вышеупомянутая схема оптимизации действительно может использоваться в повседневной модульной разработке, но, пожалуйста, оптимизируйте ее в соответствии с анализом сценария приложения для ваших собственных потребностей.При неправильном использовании оптимизация может привести к снижению производительности.