Я не могу сказать, какие 6 форматов может выводить накопитель 😥 Почти презираемый

внешний интерфейс JavaScript
Я не могу сказать, какие 6 форматов может выводить накопитель 😥 Почти презираемый

Когда я раньше искал работу, потому что написал в резюме "умелое использование"rollup.jsпостроить", но нет ответаrollupКакие форматы могут быть упакованы, интервьюер меня чуть не презирал.

Это действительно не должно!

Поэтому я заново выучил и разобрал его, и поделился им со всеми.

Изучите эту статью 📖

Ты будешь:

  1. Разберитесь в нескольких форматах вывода vite и rollup, поймите их взаимосвязь и сценарии использования.
  2. получить самый простойrollup.jsПакетdemoодна порция.
  3. этоdemoТакже для каждого результата упаковки подготавливается исполняемый файл.demo of demo

Зачем этому учиться?

сопровождаемыйvite.jsвсе больше и огонь, он также превратился в производство работы иИнтервью Вопросы и ответычасто задаваемый вопрос.

Как мы все знаем,vite.jsЯдром сборки являетсяrollup.js.

Так почему же необходимо учиться, прежде чем изучать ихjsМодульная спецификация?

Потому что нам нужно понять, каков их конечный продукт и как они работают.

«Поклонение магии» — табу для изучающих программирование, а «любопытство» — это лестница для нашего роста и прогресса.

Давайте разгадаем тайну и посмотрим на запакованный код, это все "что"!

ДЕМО и пример сборки

пожалуйста, сотрудничайтеdemoЕшьте, и вы получите больше!

Я построил простой для этой статьиdemoНапример, исходный код находится вgithubначальство.

demoадрес:GitHub.com/Начало розыгрыша…
demoСтруктура кода следующая:

├── answer.js
├── index.js
├── out
├── package.json
├── rollup.config.js
└── yarn.lock

вindex.jsа такжеanswer.jsОн принадлежит бизнес-коду и является объектом, который необходимо упаковать. существуетindex.jsзависел отanswer.js.
следующим образом:

// answer.js
export default 42

// index.js
import answer from "./answer";
import { repeat } from 'lodash'
// 定义一个无用变量, 测试 tree-shaking
const unusedVar = 'May the 4th'

export const printAnswer = () => {
  // 打印
  console.log(`the answer is ${answer}`)
  // 测试 lodash 的能力,打印42个1
  console.log(repeat('1', answer))
}

rollup.config.jsдаrollupconfig, где мы отдельно указываем его выводamd , cjs , esm , iife , umd , systemФайлы в шести форматах.

Выходной файл будет упакованoutпод папку.

когда мы выполняемyarn buildилиnpm buildПосле этого будетoutКод ниже создает следующий формат:

├── out
│   ├── amd
│   │   └── bundle.js
│   ├── cjs
│   │   └── bundle.js
│   ├── ems
│   │   └── bundle.js
│   ├── iife
│   │   └── bundle.js
│   ├── system
│   │   └── bundle.js
│   └── umd
│       └── bundle.js

Чтобы понять каждый форматbundle.jsКак работает файл, я специально добавляю некоторые подчиненные в некоторые из них.demo.

Далее давайте изучим и проанализируем формат за форматом.勇敢牛牛

1. Самовыполняющаяся функция IIFE

Полное название IIFE — «немедленно вызываемое функциональное выражение».

1.1 Анализ результатов упаковки

Давайте посмотрим на БенаdemoизiifeКак выглядит отформатированный пакет.

IIFE

Некоторые упрощения приведенного выше кода:

var Test = (function (exports, lodash) {
  'use strict'; // 自带严格模式,避免一些奇怪的兼容性问题

  /**
   * 下面折行无用代码被 tree-shaking 掉了
   * const unusedVar = 'May the 4th'
   * */

  var answer = 42; // 业务中被单一引用的模块,被直接抹平了

  const printAnswer = () => {
    console.log(`the answer is ${answer}`);

    console.log(lodash.repeat('1', answer));
  };

  exports.printAnswer = printAnswer; // 把要export的属性挂在到exports上

  return exports;

})({}, $); // exports是第一个入参,依赖的jquery是第二个入参

IIFEЭто ранний продукт модуляризации интерфейса, основная идея которого заключается в следующем:

  1. Создайте анонимную функцию
  2. Немедленно выполнить эту анонимную функцию, а внешние зависимости передаются в виде параметров
  3. Возвращает вывод этого модуля

1.2 Как это работает

IIFEОперация на самом деле очень проста, если у нее нет других зависимостей, просто импортируйте файл, а затем вwindowПросто возьмите соответствующую переменную.
Такие как:

  <script src="http://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  <script> 
    // jquery 就是典型的自执行函数模式,当你引入后,他就会挂在到 window.$ 上
    window.$ // 这样就能取到 jquery 了
  </script>

Но если ты как БенdemoЕсли вы зависите от других модулей, таких как в , вы должны убедиться, что следующие две вещи работают правильно:

  1. Пакет, от которого зависит этот пакет, был загружен до этого пакета.
  2. предварительно зависимые пакеты иIIFEИмена переменных, которые выполняют только входные параметры, согласованы.

этимdemoизIIFEПостройте результат в качестве примера:

  1. он имеет предварительную зависимостьlodash, так что это нужно сделать до того, как он загрузитсяlodashнагрузка.
  2. этоIIFEВторой доход этоlodash, в качестве предварительного условия, мы должны позволитьwindow.lodashтакже указывает наlodash.

Итак, при запуске код выглядит следующим образом:

<head>
  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
  <script>window.lodash = window._</script>  
  <script src="./bundle.js"></script>
</head>
<body>
  <script>
    window.Test.printAnswer();
  </script>
</body>

1.3 Преимущества и недостатки

  • преимущество:
    1. Замыкания создают «частное» пространство имен, предотвращая глобальные эффекты и предотвращая изменение частных переменных извне.
    2. Легко понять
    3. Незначительное влияние на размер кода
  • недостаток:
    1. Экспортируемые переменные могут влиять на глобальные переменные; глобальные переменные используются при импорте зависимых пакетов.
    2. Поддерживается пользователемscriptПорядок загрузки тегов.

Преимущества не будут подробно обсуждаться, а недостатки будут подробно объяснены.

Недостаток 1: выходные переменные могут влиять на глобальные переменные; при импорте зависимых пакетов полагайтесь на глобальные переменные.

Первая половина предложения:Выходные переменные могут влиять на глобальные переменные;На самом деле, это легко понять, вышеdemoПример вывода:window.Testуже пострадал.
Этот очевидный побочный эффект на самом деле является скрытой опасностью в программе.

Вторая половина фразы:Зависеть от глобальных переменных при импорте зависимых пакетов;мы делаемdemoОн работает нормально, поэтому я добавил строку кода, позволяющуюwindow.lodashтакже указывает наlodash, но он действительно слишком хрупкий.

<!-- 没有这一行,demo就无法正常运行 -->
<script>window.lodash = window._</script>

Смотреть,IIFEЗависимость реализации от окружения жесткая, если только она вообще не зависит от внешних пакетов. (Jquery: Точно ниже!)

несмотря на то чтоIIFEНедостатков много, но это не мешаетJqueryВремя очень способствовалоwebпроцесс разработки, поскольку он разрешаетjsСам по себе много проблем.

Так? Есть ли продолжениелучшеВышло фронтенд модульное решение?

Конечно есть, см. ниже.

2. ОбщийJS

2.1 Анализ результатов упаковки

Первый взглядCommonJsУпакованный результат:
cjsУпрощенно это выглядит так:

'use strict';

var lodash = require('lodash');

var answer = 42;

const printAnswer = () => {
  // 打印
  console.log(`the answer is ${answer}`);
  // 测试 lodash 的能力,打印42个1
  console.log(lodash.repeat('1', answer));
};

exports.printAnswer = printAnswer;

Вышеупомянутый форматCommonJSСтандартное письмо.

// CommonJS 通过一个全局 require 方法进行模块的引入 
var lodash = require('lodash');
// CommonJS 进行模块内方法输出的方式
module.exports.printAnswer = printAnswer;
// 上面写法也等价于:
exports.printAnswer = printAnswer;
// 因为 exports 变量等价于 module.exports

чтобы решитьnode.jsотсутствие модульности,октябрь 2009 г. CommonJSСначала была предложена спецификация.

Обратите внимание на это ключевое слово:node.js.

Да,CommonJSне спецификация, работающая в среде браузера, аnode.jsдействующие в окружающей среде.

2.2 Как бегать

Поэтому я написалrun.jsсценарий. следующим образом:

// run.js
const Test = require('./bundle.js')
Test.printAnswer()

Затем выполните следующую команду:

# 执行脚本
node ./out/cjs/run.js 
# 输出1: 
> the answer is 42
# 输出2: 
> 111111111111111111111111111111111111111111

Как можно заметить,node.jsОкружающая среда является естественной опоройCommonJSиз.

2.3 Преимущества и недостатки

  • преимущество
  1. Идеальное модульное решение, идеальное решениеIIFEразличные недостатки.
  • недостаток
  1. Среда браузера не поддерживается, так как такой способ синхронизации может привести к зависанию браузера.

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

3. AMD и requirejs!

АМД, ДА!

2011 год,amdjs-apiЭто было официально предложено в отрасли.

3.1 Анализ результатов упаковки

Результат упаковки в формате amd выглядит следующим образом:amd,yes!Как видите, основной контент — это глобальный методdefine.

defineМетод имеет три входных параметра, а именно:

  • "Test", имя модуля
  • [exports, lodash]Представлять выходные данные модуля и внешних зависимостей соответственно.
  • один сexportsа такжеlodashВ качестве метода ввода он представляет фактическое содержимое модуля.

в сравнении сIIFEа такжеCommonJsС точки зрения,AMDНаписано, конечно, сложно и неудобно.

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

особенноamdСтандартная реализация:requirejs.

requirejsдостигнутоAMDне только решенCommonJSНеудобство со стороны браузера, загрузка модуля асинхронно реализует возможность не вызывать зависания анимации, полностью компенсирует егоIIFEразличные дефекты.

requirejsПри использовании обычно используется следующий четырехэтапный метод:

  1. Представить в браузереrequire.js
  2. пройти черезrequirejs.configМетод определяет глобальные зависимости
  3. пройти черезrequirejs.defineмодуль регистрации
  4. пройти черезrequirejs()Завершите импорт модуля.

3.2 Как бегать

существуетout/amdв каталоге пакетаindex.html, расположите код следующим образом:

<head>
  <!-- 1. 引入 require.js -->
  <script src="./require.js"></script>
  <!-- 2. 定义全局依赖 -->
  <script>
    window.requirejs.config({
      paths: {
        "lodash": "https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min"
      }
    });
  </script>
  <!-- 3. 定义模块 -->
  <script src="./bundle.js"></script>
</head>
<body>
  <script>
    // 4. 开销模块
    window.requirejs(
      ['Test'],
      function   (test) {
        test.printAnswer()
      }
    );
  </script>
</body>

Откройте браузер, мы обычно видим] консоль распечатывается42а также42个1.

3.3 Преимущества и недостатки

  • преимущество
  1. решеноCommonJSНедостатки
  2. решеноIIFEНедостатки
  3. в полноценном браузереjsФайловая модульная схема
  • недостаток
  1. Организация кода неудобная, читабельность плохая.

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

Теперь у нас естьориентированныйnode.jsизCommonJsа такжеориентированный на браузерAMDДва набора стандартов.

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

4. Отличная интеграция UMD

Он не сделал ничего новаторского, но он был мастером.

4.1 Анализ упаковки

umdЧитаемость кода, созданного из формата, еще больше снижается.

Я уверен, что любой нормальный человек получит головную боль, когда увидит следующий код:

umd bundle

Да, целый большой кусок кода просто занимается проблемами совместимости и решает, что его следует использовать в настоящее время.amdилиCommonJS.

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

4.2 Как это работает?

  • Со стороны браузера, как это работает иamdТочно так же, вы можете заполнить ссылку3.2фестивальdemo.
  • На стороне node.js он работает сCommonJSРежим работы точно такой же и здесь повторяться не буду.

4.3 Преимущества и недостатки

  • преимущество
    1. разгладил пакет вAMDа такжеCommonJSразница в
  • недостаток
    1. Это создаст много плохо понятного кода для совместимости. (Понимание сложности и размера пакета)

Несмотря на постоянные усилия сообщества,CommonJS,AMD,UMDВсе дали свои ответы отрасли.

Но очевидно, что все это варианты последней инстанции.

Браузеры должны иметь свои собственные критерии загрузки.

ES6В черновике хоть и описывается, как должны загружаться модули, но нет «спецификации для загрузчика».

5. Системные J

следовательноWHATWG(Web Hypertext Application Technology Working Group)То есть Рабочая группа по технологиям веб-гипертекстовых приложений предложила набор более перспективных спецификаций:whatwg/loader.

то естьJavaScript Loader Standard(JS загружает стандарт).

Эта спецификация описывает поведение при загрузке модулей JavaScript из среды размещения JavaScript. Он также предоставляет API для перехвата процесса загрузки модуля и настройки поведения загрузки.

На основании этой спецификации,SystemJSРодился.

SystemJSВ настоящее времяwhatwg/loaderРекомендации по спецификациям.

systemjs bundle

Видно, что,systemРезультат упаковки на самом деле такой же, какamdТочно так же предоставляется глобальный объектSystem, а также предоставляет метод регистрации и единый метод записи.

Только по результатам упаковки я не вижу, чтобы это сравнивалосьAMD + require.jsКаковы преимущества,Просто разница в написании?

И это не останавливаться на достигнутом!

в сравнении сrequire.js,SystemJSизSystem.import('module/name')способ позволяет загружать модули более "лениво", а это значит, что вам не нужно загружать целую кучуbundle, пользователю нужно тратить пропускную способность только на те страницы, которые он может видеть.

Кроме того, посколькуSystemJSэто дляwhatwg/loaderПрактика спецификации, так что это перспективный способ зависимостей модулей.

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

6. ЭСМ

Модули ECMAScript, также известные как ESM, официальный стандартный формат модульности Javascript.

6.1 Анализ упаковки

существуетESMДо того, как это было предложено, в JavaScript не было настоящей модульной системы.

Его стандарт переданexportКоманда явно указывает выходной код, а затем передаетimportввод команды.

// 导入模块
import { foo } from 'bar';
// 导出命令
export { zap };

Это также самый привычный способ письма в нашем повседневном развитии.

следовательно,esmПакет, отформатированный в формате, действительно очень читабелен:esm

Это ничем не отличается от чтения бизнес-кода, который мы обычно пишем. (rollupеще не забыл сделатьtree-shaking)

6.2 Как бегать

Поздравляем, вы передовая разработка этой эпохи.

Некоторые современные браузеры начали реализовывать<script type="module>, поэтому используйте его прямо в браузереesmстало реальностью.

Но для его запуска и запуска требуется несколько предварительных шагов.

  1. Запустите локальный статический сервис в каталоге js-modules
# 在js-modules目录下起一个本地静态服务
cd js-modules && http-server
  1. Пучокesm/bundle.jsПервая строка файла изменена на:
import repeat from '../../node_modules/lodash-es/repeat.js';
// 因为默认的lodash并不是输出的 esm 格式,因此为了demo我们需要做一些特殊处理
  1. Откройте страницу в браузере (при условии, что порт 8080), затем откройте:http://127.0.0.1:8080/out/esm/index.html

Таким образом, код работает успешно, и консоль успешно печатает42а также42个1.

Резюме: В каких сценариях они подходят для использования?

  • IIFE:Он подходит для использования в качестве SDK в некоторых сценариях, особенно если вам нужно подключиться кwindowсцена выше.
  • CommonJS:Библиотеки, используемые только node.js.
  • AMD:Сценарии, которые нужно использовать только на стороне браузера.
  • UMD:Сценарии, которые можно использовать как на стороне браузера, так и в node.js.
  • SystemJs:Аналог УМД. в настоящее время более известенAngularВот для чего он используется.
  • ESM:1. Сценарии, на которые будут ссылаться и которые будут перекомпилированы (такие как библиотеки компонентов и т. д.) 2. Сценарии отладки браузера, такие какvite.jsразвития. 3. Сценарии с очень плохой совместимостью с браузерами.

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

я春哥.
Я люблюvue.js , ElementUI , Element PlusСтек родственных технологий, моя цель - поделиться самыми практичными и полезными знаниями, надеюсь, мы сможем пораньше оторваться от работы, и сможем быстро завершить свою работу, спокойной рыбалки в неспокойной воде 🐟.

ты сможешьНаггетсСледуй за мной или вНет публикинайди меня в:前端要摸鱼.
Я надеюсь тебе весело.