До того, как была предложена спецификация CommonJs, в Javascript не было модульной системы, а это означало, что нам было сложно разрабатывать крупномасштабные приложения, поскольку организация кода была бы сложнее.
Прежде всего, CommonJS не уникален для Node. CommonJS — это спецификация модуля, которая определяет, как ссылаться на модули и экспортировать их. Nodejs только реализует эту спецификацию. Спецификация модуля CommonJS в основном разделена на три части: ссылка на модуль, определение модуля и идентификация модуля. .
Ссылка на модуль
Ссылка на модуль означает, что мы можем ввести другие модули через require
.
const {add} = require('./add'); const result = add(1,2);
Модуль определяет
файл как модуль, и модуль предоставляет две переменные, а именно модуль и экспорт. модуль — это сам текущий модуль, экспорт — это содержимое, которое нужно экспортировать, а экспорт — это атрибут модуля, то есть экспорт — это модуль.exports. Содержимое, импортируемое другими модулями через require, является содержимым модуля.exports.
// добавить.js Exports.add = (a, b) => { вернуть а + б; }
Идентификация модуля
Идентификация модуля — это содержимое require. Например, require('./add')
, тогда идентификатор модуля будет ./add
.
Механизм импорта и экспорта модулей, созданный с помощью CommonJS, позволяет пользователям легко создавать крупномасштабные приложения без необходимости учитывать переменное загрязнение.
Реализация узла узла
Node реализует спецификацию CommonJs и добавляет некоторые необходимые функции. Node в основном выполняет следующие три вещи для реализации спецификации CommonJs:
Позиционирование файла
анализа пути
, компиляция и выполнение
анализа пути.
При выполнении require() параметром, полученным методом require, является идентификатор модуля, и узел выполняет анализ пути через идентификатор модуля. Целью анализа пути является поиск пути, по которому находится этот модуль, по идентификатору модуля. Прежде всего, узловые модули делятся на две категории: базовые модули и файловые модули. Базовый модуль — это модуль, поставляемый с узлом, а файловый модуль — это модуль, написанный пользователем. При этом файловые модули делятся на файловые модули в виде относительных путей, файловые модули в виде абсолютных путей и файловые модули в виде непутей (например, экспресс).
Когда узел находит файловый модуль, он скомпилирует, выполнит и кэширует модуль. Общий принцип заключается в использовании полного пути к модулю в качестве ключа и скомпилированного содержимого в качестве значения. Это не потребуется при введении модуля. Затем выполните анализ пути, расположение файла, компиляцию и выполнение этих шагов. Скомпилированный контент можно прочитать непосредственно из кэша.
//Схема модуля кэша: константный кэшированныйМодуль = { '/Usr/file/src/add.js': 'Скомпилированное содержимое add.js', 'http': 'Скомпилированное содержимое модуля http, поставляемого с Node', 'express': 'Скомпилированное содержимое пользовательского файлового модуля без пути' // ... }
Если вы хотите найти модуль, импортированный с помощью require, порядок поиска модуля заключается в том, чтобы сначала проверить, находится ли модуль уже в кеше. Если его нет в кеше, затем проверьте основной модуль, а затем выполните поиск. файловый модуль. Среди них легче найти файловые модули в виде путей. Полный путь к файлу можно получить на основе относительного или абсолютного пути. Найти пользовательские файловые модули в форме, отличной от пути, относительно сложно. Node будет искать файл в папке node_modules.
Где находится каталог node_modules? Например, файл, который мы сейчас выполняем, — /Usr/file/index.js
/**; * /Usr/file/index.js; */ const {добавить} = требуется('добавить'); const result = add(1, 2);
В этом модуле мы добавили модуль add. Это дополнение не является ни основным модулем, ни файловым модулем в форме пути. Итак, как найти модуль add?
У модуля есть атрибут пути. Путь для поиска добавляемого модуля указан в атрибуте paths. Мы можем ввести этот атрибут, чтобы посмотреть:
/**. * /Usr/file/index.js; */ console.log(module.paths);
Мы можем распечатать значения путей, выполнив node index.js в каталоге файлов. Значение в путях представляет собой массив следующим образом:
[ '/Usr/file/node_modules', '/Usr/node_modules', '/node_modules', ]
То есть Node будет последовательно искать в указанном выше каталоге, содержит ли он модуль add. Принцип аналогичен цепочке прототипов. Сначала начните поиск в папке node_modules в каталоге того же уровня, что и текущий исполняемый файл. Если каталог node_modules не найден или не существует, продолжайте поиск до верхнего уровня.
Анализ путик файлу
и местоположение файла используются вместе. Идентификатор файла может быть без суффикса, либо каталог или пакет можно найти с помощью анализа пути. В этом случае поиск конкретного файла требует некоторой дополнительной обработки.
Анализ расширения файла
const { add } = require('./add');
Например, в приведенном выше коде идентификатор файла не имеет расширения. В этот момент узел будет искать наличие .js, .json. и .node последовательно.
Анализ каталога и пакета
аналогичен приведенному выше коду. То, что можно найти с помощью ./add
может быть не файлом, а каталогом или пакетом (о том, каталог это или пакет, можно судить по тому, существует ли пакет). json в папке добавления). На данный момент шаги по позиционированию файла следующие:
Если в package.json нет основного поля, индекс также будет использоваться как файл, а затем будет выполнен анализ расширения для поиска файла с соответствующим суффиксом. .
Компиляция модулей
Основные модули, с которыми мы сталкиваемся при разработке, — это модули json и модули js.
Компиляция модуля json
Когда нам нужен модуль json, Node фактически поможет нам использовать fs.readFilcSync для чтения соответствующего файла json, получения строки json, а затем вызвать JSON.parse для анализа, чтобы получить объект json, а затем назначить его модуль экспортирует, а затем отдает его по запросу.
компиляция модуля js
Когда нам нужен модуль js, например
// index.js const { add } = require('./add');
// add.js Exports.add = (a, b) => { вернуть а + б; }
Что произошло в этот момент? Почему мы можем использовать модуль переменных, экспорта и запроса прямо в модуле? Это связано с тем, что Node сначала и в последнюю очередь оборачивает содержимое модуля при компиляции js-модуля.
Например, модуль add.js при фактической компиляции будет упакован в структуру, подобную этой:
(function(require, Exports, Module) { Exports.add = (a, b) => { вернуть а + б; } вернуть модуль.экспорт; })(require,module.exports,module)
То есть написанный нами js-файл будет упакован в функцию. То, что мы пишем, — это только содержимое в этой функции, а последующий процесс упаковки Node от нас скрыт. Эта функция поддерживает передачу некоторых параметров, включая require, экспорт и модуль.
После компиляции файла js он будет выполнен. Node передаст соответствующие параметры этой функции, а затем выполнит ее и вернет значение модуля.exports функции require.
Выше приведен основной процесс реализации спецификаций CommonJs для Node.