Советы по чтению. Многие внешние ссылки в этой статье требуют научного доступа в Интернет.
Для тех, кто плохо знаком с JavaScript, может быть сложно увидеть «CommonJS против AMD», «Requirejs против Seajs», «Webpack против Browserify» и т. д.
Особенно теперь, когда большинство браузеров внедрили модульную спецификацию ES6, наши недавно разработанные проекты — это в основном ES6 с Webpack Эти AMD, CMD, UMD, Requirejs, Seajs уже в прошлом, и многие студенты не используют.
Но модульность является частью системы разработки JavaScript, и стоит знать ее историю, по крайней мере, не теряя возможности поговорить с другими разработчиками в этой области, например, с вашим интервьюером.
Foreword
С момента выпуска JavaScript в 1995 году загрузка модулей JS на стороне браузера выполнялась с использованием простых тегов script. Уже в 1996 г. многиеРеализация JavaScript на стороне сервера, такие как Nodejs, выпущенный в 2009 году. Будь то браузерный или серверный JavaScript, до того, как была предложена спецификация ES6, сам JavaScript не имел модульной системы.
Так что же такое модуль?
Хорошие авторы делят свои книги на главы, а хорошие программисты делят свои программы на модули. Хорошие модули очень автономны, специфичны для каждой функции, и их можно модифицировать, удалять или добавлять по мере необходимости, не нарушая работу всей системы.
Каковы преимущества модульности?
Преимущества модульности заключаются в основном в следующем:
- Пространства имен
В JavaScript интерфейс каждого JS-файла представлен в глобальной области видимости, каждый может получить к ним доступ, и легко вызвать загрязнение пространства имен. Модульность может создать личное пространство для переменных, чтобы избежать загрязнения пространства имен.
- возможность повторного использования
Вы когда-нибудь копировали ранее написанный код в новый проект? Если вы разделите этот код на модули, вы сможете использовать его снова и снова, и вам нужно изменять этот модуль только тогда, когда вам нужно его изменить, а не в каждом таком коде в вашем проекте.
- ремонтопригодность
Модули должны быть автономными, а хорошо спроектированный модуль должен иметь как можно меньше зависимостей от частей кодовой базы, чтобы его можно было удалять и модифицировать независимо. Когда модули отделены от других фрагментов кода, гораздо проще обновлять отдельные модули и версионировать каждое изменение.
Традиционный модульный метод разработки
Когда несколько файлов JS используют одно и то же имя для переменных и методов и вызывают конфликты имен, можно использовать пространство имен в Java.
// 代码来自:https://github.com/seajs/seajs/issues/547
var org = {};
org.CoolSite = {};
org.CoolSite.Utils = {};
org.CoolSite.Utils.each = function (arr) {
// 实现代码
};
org.CoolSite.Utils.log = function (str) {
// 实现代码
};
Подобно тому, как классы используются в других языках программирования, таких как Java или Python, общедоступные, а также частные методы и переменные могут храниться в одном объекте. Напишите методы, которые должны быть представлены в глобальной области вне замыкания, и инкапсулируйте частные переменные и методы в области замыкания, чтобы решить проблему, связанную с доступностью переменных в глобальной области.
// 全局作用局可访问
var global = 'Hello World';
(function() {
// 只能在闭包内访问
var a = 2;
})()
Хотя этот подход имеет свои преимущества, он также имеет свои недостатки.
- Модуль, определяемый фабричной функцией немедленного вызова (IIFE: выражение функции немедленного вызова).
- Ссылки на зависимости выполняются через имена глобальных переменных, загружаемых через теги сценария HTML.
- Зависимости очень слабые: разработчикам нужно знать правильный порядок зависимостей. Например, файлы, использующие Backbone, не могут предшествовать тегам jQuery.
- Требуются дополнительные инструменты для замены набора тегов сценария одним тегом для оптимизации развертывания.
Это может быть трудно управлять в больших проектах, особенно когда сценарии имеют много зависимостей, перекрывающихся и вложенных друг в друга. Рукописные теги сценариев не очень масштабируемы, и у них нет возможности загружать сценарии по запросу.
Есть ли способ не запрашивать зависимые модули в глобальной области, а запрашивать зависимые модули внутри модуля? Появились CommonJS, AMD, CMD, UMD и т. д. Эти модульные спецификации сообщают разработчикам:
- Как импортировать зависимости модуля (импорт)
- Как определить модуль (код)
- Как экспортировать интерфейс модуля (экспорт)
С тех пор, как была выдвинута идея модульной разработки, разработчики изучают модульные спецификации и реализации, отвечающие реальным потребностям, будь то разработка Javascript на стороне браузера или на стороне сервера.Проблемы, которые им приходится решать, одни и те же, а именно модульные разработка и Проблемы с зависимостями модулей, но они инициируются по разным причинам.
CommonJS
MozillaЗапущен в январе 2009 года инженером Кевином Дангуром.ServerJSПроект направлен на стандартизацию модульности JavaScript при использовании на стороне сервера, а также на стандартизацию контента, связанного с разработкой на стороне сервера, такого как API файловой системы, потоки ввода-вывода и Socket IO.
он what-server-side-javascript-needsВ нем упоминается, что требуется для серверного JavaScript:
a cross-interpreter standard library
a handful of standard interfaces
a standard way to include other modules
a way to package up code for deployment and distribution and further to install packages
и хотелось бы, чтобы они работали на как можно большем количестве операционных систем и интерпретаторов, включая три основные операционные системы (Windows, Mac, Linux) и четыре основных интерпретатора (SpiderMonkey, Rhino, v8, JavaScriptCore), а также «браузер» (который сам по себе является уникальной средой).
Чтобы продемонстрировать широкое применение определяемого API, в августе 2009 г. ServerJS былПереименован в CommonJS.. Многие последующие разработкиПодавать жалобы, считает, что модульный формат CommonJS очень недружелюбен к браузерам (не поддерживает асинхронную запись), и относится к браузерам как к гражданам второго сорта, что больше подходит для названия ServerJS.
I also feel like CommonJS has treated browser use as a second class citizen, which may have made more sense when it was ServerJS. As it stands today, the CommonJS module format is unfriendly to the browser.
NodeJS
31 мая того же года американский программист Райан Даль реализовал проект Node.js (New server-side js project: Node), и впервые представил Node.js на конференции JSConf 8 ноября того же года (Ryan Dahl at JSConf EU 2009 Video).
Node.js, который напрямую использует спецификацию CommonJS для реализации модульной системы, очень популярен.Я полагаю, что большинство веб-разработчиков до сих пор называют модульную систему Node.js спецификацией CommonJS:
//math.js
exports.sum = function(...nums){
return nums.reduce((result, num) => result + num, 0)
}
//index.js
var math = require('math')
exports.result = math.sum(1,3);
На самом деле отношения между ними — это не то, что мы думаем о роли стандартизатора и исполнителя стандарта. В мае 2011 года Райан долженr/nodeМодератор заявки на открытиеПост с вопросами и ответами, в ответ на вопрос, что CommonJS умер и не стоит обсуждать, это был уже 2009 год:
Consider CommonJS extinct - not worth thinking further about. That was a 2009 thing.
К марту 2013 г.brettz9в этой связиВ вопросах сообщества Nodejs:
What is the reason for the indifference to CommonJS? I understand you are no longer looking to adhere to it.* Are all contributors abandoning it or just you?
Основатель npm Исаак Шлютер ответил:
A few good things came out of CommonJS. The module system we have now is basically indistinguishable from the original "securable modules" proposal that Kris Kowal originally came up with. (Of course, we went pretty far off the reservation in v0.4, with the whole node_modules folder thing, and loading packages via their "main" field. Maybe we should remove those features, I'm sure that Node users would appreciate us being more spec-compliant!)
В комментариях стандарт CommonJS стал концентрацией документов для нишевого решения JS на стороне сервера (Server Side JS), а Node.js выиграл конкуренцию серверной JS, как сказал основатель Node.js Райан Даль:
"Forget CommonJS. It's dead. We are server side JavaScript."
Node.js — это серверный JavaScript. Что еще более важно, Исаак ценил голос реальных пользователей больше, чем мнения так называемых разработчиков стандартов, а новые стандарты, предложенные рабочей группой CommonJS в то время, были скорее беспорядком (например, так называемый стандарт Package). . Фактически к 2013 г.Node.js ModulesЭто уже своя семья.
Module Loader
Еще в 2009 году веб-разработчики столкнулись с множеством<script>
Этикетка беспокоит. Как управлять зависимостями в браузере — очень хлопотная проблема. И YUI 2, и Google Closure Library предлагают решения на основе пространства имен, но им по-прежнему нужна человеческая плоть для обеспечения порядка загрузки и упаковки скриптов.
После того, как CommonJS был предложен, у некоторых людей возникли вопросыПочему CommonJS фокусируется только на стороне сервера, Кевин Дангур в своемблогПункты, выделенные специальным жирным шрифтом, относятся не только к серверу, но и к JS браузера.
In agreement on the desire to have some standardization around the areas that you've bold-ed in your post. One nit though: there's not really anything server-specific about this stuff. It applies to browser-based JS usage, and even other JS usage, like folks integrating with Gnome, Cocoa, etc.
CommonJS привержен серверной экологии JavaScript с синхронной загрузкой модулей, очень кратким синтаксисом и очень дружественным к серверной разработке. Но это неприемлемо со стороны браузера, чтение одного модуля из сети занимает больше времени, чем чтение с диска, и пока работает скрипт, который загружает модуль, он не позволяет браузеру запускать остальные, пока модуль не загрузится Готово .
существуетФорум CommonJSпо инициативе Кевина ДангураОбсуждение асинхронной загрузки модулей Commonjs так же какПризыв к решениям для загрузки модулей на стороне браузера. На форумах также было много сообщений о том, как асинхронно загружать модули Commonjs в браузере.
- предложенныйtransportРешение состоит в том, чтобы преобразовать модуль в код, который соответствует спецификации транспортировки через инструмент преобразования, прежде чем запустить его на браузере.
- Предлагается загрузить текст кода модуля с помощью XHR, а затем использовать eval или new Function для его выполнения в браузере;
- Предлагается непосредственно улучшить CommonJS, а также ввести чисто асинхронную схему загрузки модулей;
Автор третьего решения, Джеймс Берк, считает, что модульный формат CommonJS не поддерживает асинхронную загрузку на стороне браузера, необходимо загружать модули CommonJS другими методами, такими как XHR, что очень недружественно для веб-интерфейса. Разработчики. Автор считает, что наилучшей практикой для браузерной разработки является загрузка только одного модуля на страницу. так:
<!-- loader.js defines LOADER_ENTRY_FUNCTION -->
<script src="loader.js"></script>
<script>LOADER_ENTRY_FUNCTION(["page1"]);</script>
page1 模块可能长这样:
LOADER_ENTRY_FUNCTION(
"page1",
["b", "c"],
function(b, c) { //
document.addEventListener("DOMContentLoaded", function() {
//Do page setup in here, use b and c
}, false);
}
);
В режиме разработки каждый модуль можно загрузить отдельно, чтобы обеспечить наилучшие возможности отладки. Затем все зависимости модуля page1 и вложенные зависимости могут быть включены в него посредством компиляции или зависимости могут быть объединены во время выполнения с помощью loader.js.
RequireJS in AMD
Джеймс Берк, 09 декабряCommonJS in the browserВ статье я написал длинный абзац о непосредственном улучшении формата модуля CommonJS для удовлетворения требований разработки на стороне браузера, но инициатор CommonJS Кевин Дангур не согласился с этим планом, что породилоRequireJS,Процесс генерации RequireJS можно найти в ветке обсуждения, инициированной Джеймсом Бёрком:
- New amd-implement list 11/5/25
- Split off AMD? (was Re: [CommonJS] New amd-implement list)
- Harmony module execution
- AMD proposal change: define.amd
- AMD vs Wrappings
- Function.prototype.toString to discover function dependencies 10/9/16
- Updated Transport proposals 10/3/31
Джеймс Берк разработал спецификацию AMD и реализовал совместимый с AMD загрузчик модулей в 2010 году.RequireJS
. Рекомендуется посмотреть эту статью на официальном сайтеWHY AMD?
require.config({
path: {
module: './module',
}
});
require(['module/module1.js','module/module2.js'],function(module1,module2){
module1.printModule1FileName();
module2.printModule2FileName();
});
SeaJS in CMD
Юбо думать RequireJS не идеален:
- Есть возражения по срокам исполнения
- После загрузки модуля Reqiurejs он выполняется немедленно. Seajs сохраняет фабричную функцию после загрузки модуля и выполняет фабричную функцию, соответствующую модулю, когда модуль выполняется, чтобы вернуть результат экспорта модуля.
- Модульный стиль письма вызывает споры
- В стиле AMD экспорт зависимых модулей передается через параметры, что уничтожаетБлижайшее заявление в общем.
Он считает, что популярность AMD во многом зависит от раскрутки авторов RequireJS, но то, что популярно, не может быть хорошим. Он дал много комментариев команде RequireJS, но ни один из них не был принят.Упоминание в CommonJS Group:
RequireJS is good but I found that its API is annoying me. I dived into reading topics in this group, and began to implement a module loader (SeaJS) from scratch some month ago. My fellow don't like RequireJS too after using it in two projects.
Значение: RequireJS великолепен, но его API меня раздражает. После использования RequireJS в двух проектах моему коллеге это тоже не нравится. Я прочитал темы, обсуждаемые в этой группе, и несколько месяцев назад начал реализовывать загрузчик модулей (SeaJS) с нуля.
Автор RequireJS Джеймс Берк кажется немного раздраженным, увидев, что их обсуждение RequireJS и SeaJS находится в этом обсуждении.Some thought on APIs for CommonJS module loader . Джеймс Бёрк считает, что API RequireJS, предложенный Ю Бо, поддерживает их все, и Ю Бо подробно описал проблемы RequireJS:
1. В RequireJS требование имеет несколько применений, из-за чего новички могут легко ошибиться, а пользователи не могут быть хорошо поняты пользователями.
- require('a') -- gets exports of module a
- require(['a']) -- fetch module a according to module name scheme
- require(['a.js']) -- fetch a.js directly relative to current page
- require({...}) -- set loader config
2. Мне плевать на ленивое выполнение или раннее выполнение, но RequireJS API запросто может оставить мусор в коде, например:
define(['a', 'b'], function(a, b) {
a.xx();
b.yy();
});
Хотя здесь сказано, что не важно, ленивое исполнение или раннее исполнение, но вИстория фронтенд-модульной разработки, он также упомянул о проблеме времени выполнения, 囧
Сначала все было хорошо, но со временем часть кода модуля будет поддерживаться разными кодерами и код будет выглядеть так:
define(['a', 'b', 'c', ..., 'z'], function(a, b, c, ..., z) {
a.xx();
// b.yy();
z.bar();
});
Как видите, модуль b закомментирован и больше не используется. Но массив зависимостей по-прежнему содержит «b». Это очень плохо!
Конечно, мы можем заставить пользователя просто использовать другую форму, например:
define(function(require, exports) {
...
});
Но они будут знать, что это RequireJS, и потратят некоторое время на чтение документации RequireJS. Как только вы начинаете использовать его таким образом, его трудно запретить.
Помимо вышеперечисленных недостатков, Юбо считает, что у RequireJS есть следующие недостатки:
3. Он по-прежнему имеет 16 КБ после сжатия, это просто загрузчик модулей, и он должен быть меньше и быстрее.
4. Исходный код RequireJS содержит много ненужных нам функций.
Я думаю, что загрузчик должен скомпилироваться как:
- loader-for-browser.js
- loader-for-node.js
- loader-for-xx.js
loader-for-browser.js должен содержать только базовые функции загрузчика модулей в клиентском браузере. Но «require.js» содержит код для webworker, jQueryCheck, DOMContentLoaded, пакетов и т. д., которые не нужны в нашем случае использования, но мы не можем удалить этот ненужный код.
По этим причинам Yubo разработала новый загрузчик модулей: SeaJS, о котором было объявлено в CommonJS Group в ноябре 2011 г. Announcing SeaJS: A Module Loader for the Web), Sea.js следуетСпецификация CMD.
define(function(require, exports, module) {
// exports 是 module.exports 的一个引用
console.log(module.exports === exports); // true
// 重新给 module.exports 赋值
module.exports = new SomeClass();
// exports 不再等于 module.exports
console.log(module.exports === exports); // false
});
ES Module
Большая часть этой главы взята из:Блог Чена Янцзяня: Состояние интерфейсных модулей
В июне 2015 года был официально выпущен стандарт ECMAScript 6. Целью модульной спецификации ES является интеграция существующих модульных решений, таких как CommonJS и AMD, достижение модульности на уровне стандарта языка и превращение в общее модульное решение для браузеров и серверов.
Функции модуля завершаются двумя командами, экспортом и импортом. export экспортирует модули наружу, а import используется для импорта модулей.импортировать больше использования, экспортировать больше использования.
// 导入单个接口
import {myExport} from '/modules/my-module.js';
// 导入多个接口
import {foo, bar} from '/modules/my-module.js';
// 导出早前定义的函数
export { myFunction };
// 导出常量
export const foo = Math.sqrt(2);
Различия между модулем ES и CommonJS и загрузчиками в основном заключаются в следующих аспектах:
- Декларативное, а не императивное, или
import
Это оператор объявления, а не оператор выражения, который нельзя использовать в модуле ES.import
Объявление зависимостей с переменными или динамический импорт зависимостей: - Модули CommonJS выводят копию значения, модули ES6 выводят ссылку на значение.
-
import
Предварительно парсится и предварительно загружается, в отличие от RequireJS, который выполняется до точки, а затем отправляет запрос
Для прагматичных разработчиков Node.js эти различия ставят массивный код сообщества, созданный npm, в затруднительное положение, а как обновления, так и совместимость требуют много работы. В связи с этим Дэвид Херман написал статью, объясняющую,Преимущества модуля ES намного перевешивают неудобства:
-
статический
import
Гарантированно компилируется в ссылки на переменные, эти ссылки могут использоваться синтаксическим анализатором (посредством JIT-компиляции) во время выполнения в текущей среде выполнения.polymorphic inline cache) оптимизация для более эффективного выполнения -
Статический экспорт может сделать обнаружение переменных более точным, в JSHint, ESLint и других инструментах обнаружения кода определение переменных является очень популярной функцией, а статические
export
сделать это обнаружение более точным -
Более полная циклическая обработка зависимостей, в существующих реализациях CommonJS, таких как Node.js, циклические зависимости незавершены путем передачи
exports
объект разрешен, для прямых ссылокexports.foo
или переопределение родительского модуляmodule.exports
В случае с , традиционный метод не может решить эту проблему, а поскольку ES-модуль передает ссылки, таких проблем не будет.
Другие больше совместимы со стандартами, которые могут быть добавлены в будущем (макросы, системы типов и т. д.).
ES Module in Browser
До того, как вышел стандарт модуля ES, несмотря на то, что сообщество реализовало множество загрузчиков, сам браузер не выбирал модульное решение, и поддержка модуля ES меньше беспокоила браузеры.
Поскольку среда выполнения модуля ES отличается от среды выполнения обычных скриптов, расширены возможности браузера.<script type="module">
,Только<script type="module">
сценарий в (иimport
Приходит скрипт)module
модель. тоже толькоmodule
Скрипты, выполняемые в режиме, могут быть объявлены толькоimport
. То есть следующий код работать не будет:
<script>
import foo from "./foo.js"
</script>
<script type="javascript">
import bar from "./bar.js"
</script>
В настоящее время существует несколько основных вечнозеленых браузеров.Модуль ES поддерживается. Последним поддерживаемым является Firefox, а Firefox 60, выпущенный 8 мая 2018 года, официально поддерживает модуль ES.
Кроме того, учитывая обратную совместимость, браузер также увеличивается<script nomodule>
Этикетка. Разработчики могут использовать<script nomodule>
Теги совместимы с браузерами, которые не поддерживают модуль ES:
// 在浏览器中,import 语句只能在声明了 type="module" 的 script 的标签中使用。
<script type="module" src="./app.js"></script>
// 在 script 标签中使用 nomodule 属性,可以确保向后兼容。
<script nomodule src="./app.bundle.js"></script>
ES Module in Node.js
Но со стороны Node.js модуль ES намного громче. Бывший лидер Node.js Айзекс Шлютуер даже считает, что модули ES слишком круты и практичны, чтобы быть бесполезными (adds nothing).
Первый вопрос: как поддерживатьmodule
Режим выполнения, определяется ли он автоматически или'use module'
, еще вpackage.json
увеличить вmodule
как отдельную запись или просто добавить новое расширение?
В конце концов Node.js решил добавить новые расширения..mjs
:
- существует
.mjs
можно свободно использовать вimport
а такжеexport
- существует
.mjs
недоступно вrequire
- существует
.js
можно использовать только вrequire
- существует
.js
недоступно вimport
а такжеexport
То есть две модульные системы полностью независимы. Кроме того, изменился и метод поиска зависимостей, изначальноrequire.extensions
Да:
{ '.js': [Function],
'.json': [Function],
'.node': [Function] }
Теперь (нужно включить--experimental-modules
вариант) это:
{ '.js': [Function],
'.json': [Function],
'.node': [Function],
'.mjs': [Function] }
Но две независимые модульные системы также приводят ко второму запутанному аспекту: как модульные системы взаимодействуют друг с другом? Для браузеров это не проблема, но для Node.js необходимо учитывать огромное количество модулей CommonJS в npm.
Окончательный план довольно прост, в.mjs
, разработчики могутimport
CommonJS (правда, толькоimport default
):
import 'fs' from 'fs'
import { readFile } from 'fs'
import foo from './foo'
// etc.
существует.js
, разработчики естественно не могутimport
Модуль ES, но они могутimport()
:
import('./foo').then(foo => {
// use foo
})
async function() {
const bar = await import('./bar')
// use bar
}()
Обратите внимание, что, в отличие от того, как браузер определяет режим работы путем импорта, режим работы скрипта в Node.js привязан к расширению. Тем не менее, зависимости просматриваются по-разному:
- существует
.js
серединаrequire('./foo')
находясь в поиске./foo.js
или./foo/index.js
- существует
.mjs
серединаimport './bar'
находясь в поиске./bar.mjs
или./bar/index.mjs
Воспользовавшись этими функциями, мы теперь можем обновить существующие модули npm до модулей ES и по-прежнему поддерживать подход CommonJS.
Dynamic Import
статическийimport
лучший выбор для инициализации загруженных зависимостей с использованием статическогоimport
Легче с помощью инструментов статического анализа кода иtree shakingвыгода от. Но когда вы хотите загружать модули по определенным условиям или по запросу, вам нужно динамически импортировать зависимости, например:
if (process.env.NODE_ENV !== 'production') {
require('./cjs/react.development.js')
} else {
require('./cjs/react.production.js')
}
if (process.env.BROWSER) {
require('./browser.js')
}
С этой целью Доменик Деникола разработалimport()
стандартныйпредложение.
//这是一个处于第三阶段的提案。
var promise = import("module-name");
Помимо возможности обрабатывать динамические зависимости, тег скрипта в HTML не нужно объявлять.type="module"
.
<script>
import('./foo.js').then(foo => {
// use foo
})
</script>
В Node.js (.js
file) также можно использовать import() для импорта модулей ES, которые используют импорт:
import('./foo.mjs').then(foo => {
// use foo
})
Вполне возможно использовать модуль ES для написания общего модульного кода JavaScript для браузеров и Node.js. Нужны ли нам инструменты для компиляции или упаковки?
Module Bundler
Большая часть этой главы взята из:Блог Чена Янцзяня: История интерфейсных модулей
Есть также много недостатков в использовании загрузчиков модулей на стороне браузера. Например, метод кодирования RequireJS не является дружественным, загружать модули других спецификаций проблематично, и он выполняется заранее.Правила SeaJS постоянно меняются, что приводит к различным проблемам при обновлении.Однако использование CommonJS на стороне сервера очень удобен и стабилен, а для обращения к сторонним библиотекам требуется всего три простых шага.
- Настройте имя модуля и номер версии в Package.json
- npm установить установить модуль
- Импортируйте напрямую, используя require
Можно ли вводить модули в браузер, используя спецификацию CommonJS, и легко вызывать модули других спецификаций?
Одно решение состоит в том, чтобыпредварительно скомпилировано, мы используем спецификацию CommonJS для написания определений кода и импорта модулей, а затем компилируем модули и зависимости в файл js, который мы называем bundlejs.
Browserifyа также webpackВсе это предварительно скомпилированные модульные решения.В конце сборки создается пакетный файл, а зависимости разрешаются в процессе сборки.
Browserify
Ранний активный член сообщества Node.js Разработка подстековBrowserifyПервоначальный замысел очень прост:
Browsers don't have the
require
method defined, but Node.js does. With Browserify you can write code that usesrequire
in the same way that you would use it in Node.
Browserify[Github]Это позволяет вам использовать метод, аналогичный методу node require(), для организации кода Javascript на стороне браузера.Благодаря предварительной компиляции внешний интерфейс Javascript может напрямую использовать некоторые библиотеки, установленные Node NPM, и вы также можете ввести не- Модули CommonJS, но вам нужно использовать преобразование (browserify .transform настраивает плагин преобразования).
Просматриватьrequire
В соответствии с Node.js асинхронная загрузка не поддерживается. Как видно, желание сообщества, чтобы Browserify поддерживал асинхронную загрузку, было высоким:Support for asynchronous loading (and not packing everything in one file), но автор настаивает на том, что Browserifyrequire
Должен соответствовать Node.js:
1: wrapping a whole file in a function block is ugly
2: node modules use synchronous requires
3: browserify's goal is to let code written for node run in the browser
Webpack
Выпущен на год позже, чем BrowserifyWebpackСочетая преимущества и недостатки CommonJS и AMD, вы можете следовать методу написания CommonJS во время разработки и поддерживать загрузку по требованию и асинхронную загрузку всех ресурсов после компиляции.
Наиболее выдающейся особенностью Webpack является его модульная детализация синтаксического анализа и мощные возможности упаковки, а вторая — его расширяемость.Связанные инструменты преобразования (Babel, PostCSS, модули CSS) могут быть превращены в плагины для быстрого доступа, а также Пользовательский загрузчик. В совокупности эти характеристики неисчерпаемы.
И это также поддерживаетES Module:
import defaultExport from "module-name";
import * as name from "module-name";
import { export } from "module-name";
Это преимущество инструмента сборки, который гораздо более мощный, чем традиционный загрузчик браузера, и может легко добавить поддержку трансполютора, такие как Babel и Traceur.
Еще рекомендуемое чтение:
Afterword
как ЮбоИстория фронтенд-модульной разработкиВ нем говорилось: «С быстрым развитием W3C и других спецификаций, а также быстрым развитием браузеров модульная разработка внешнего интерфейса постепенно станет инфраструктурой. Все когда-нибудь станет историей.
Нам больше не нужно ломать голову над тем, какое модульное решение использовать в нашей разработке: ES6 решает эту проблему за нас на уровне языкового стандарта.
Time Line
- В 2009 году американский программист Райан Даль создал проект node.js Модульная система node.js написана со ссылкой на спецификацию модулей CommonJS.
- Но запрос в спецификации CommonJS синхронизируется, что недопустимо в браузере. Позже появилась спецификация AMD, а в 2010 году Requirejs реализовал спецификацию AMD.
- С 2012 года Юбо чувствовал, что RequireJS недостаточно совершенен, и многие предложения команде RequireJS не были приняты, поэтому он сам написал Sea.js и сформулировал спецификацию CMD, которая следует спецификации CMD.
- В июне 2015 года был официально выпущен стандарт ECMAScript6, реализующий функцию модуля на уровне языкового стандарта, который может полностью заменить спецификации CommonJS и AMD и стать общим модульным решением для браузеров и серверов. (это будущее)
- В октябре 2015 года появился UMD, объединяющий методы CommonJS и двух спецификаций определения модулей AMD. В настоящее время стандарт модуля ES6 только что вышел, и многие браузеры еще не поддерживают спецификацию модуля ES6.
- Браузерная версия 2016 г.
- Выпуск веб-пакета 2017 г.
Current Situation
- CommonJS
- NodejsStart 67.3k стал стандартом серверного JavaScript
- Загрузчик модулей (загрузчик модулей ушел в прошлое)
- RequireJS [GitHub]Старт: 12.4k, больше не поддерживается
- seajs[Github]Старт: 8k, больше не поддерживается. Автор опубликовал Weibo в 2015 году: «Дереву Sea.js нужно поставить надгробную плиту».
- ES6 Module
- Синтаксис поддерживается основными браузерами и Nodejs 8.5 и выше, проверьтеСовместимость с браузером.
- Module Bundler
- webpack [GitHub]Звезда: 52,5k, сейчас самый популярный инструмент для упаковки
- browserify [GitHub]Звезда: 13k, обновлено в ноябре 2019 г.
Наконец, на эту статью частично ссылаются или выдержки из следующих статей: