Сегодня, в 2017 году, многие вечнозеленые браузеры поддерживают модули ES6 из коробки. В некоторых браузерах он скрыт за флагом, в том числе в Node.js. Но можно ли поддерживать старую и новую среду одним и тем же пакетом npm? Да!
Примечание редактора. Модули ES6 иногда называют модулями ES2015, ESM или
module
скриптами, а иногда даже расширением.mjs
, которое произносится как «скрипты Майкла Джексона». Мы все говорим об одном и том же, поэтому не запутайтесь, если услышите разные термины.
Я не буду вдаваться в подробности использования модулей ES6 или почему TypeScript - это круто, потому что в блогах было много сообщений, подробно описывающих их. Вместо этого я сосредоточусь на публикации пакета в npm, который написан на TypeScript, но развернут как .mjs
(ESM) и .js
(CommonJS), чтобы любой потребитель мог использовать ваш пакет!
Начиная
Первый шаг - настроить ваш tsconfig.json
файл так, чтобы TypeScript использовал новейшие и лучшие функции JavaScript, например:
{
"compilerOptions": {
"module": "es2015",
"target": "ES2017",
"rootDir": "src",
"outDir": "dist",
"sourceMap": false,
"strict": true
}
}
Очевидно, мы хотим, чтобы модули были es2015
, потому что это в заголовке этой статьи, поэтому мы должны решить это в какой-то момент! Давайте нацелимся на es2017
, чтобы мы могли использовать ключевые слова async
и await
, как JS Ninja. Вы можете называть свои rootDir
и outDir
как хотите, но это своего рода соглашение использовать dist
для вывода в JS Land. Карты источников не являются обязательными, но я предпочитаю отключать их, пока они мне не понадобятся. Строгий режим также является необязательным, но проще начать строгий и получить немного расслабленного тупого духа, если вам понадобится слишком поздно. Я настоятельно рекомендую включить его, так как по умолчанию он отключен.
Подключение его
Теперь мы можем обсудить файл package.json
. Вот пример пакета под названием copee:
{
"name": "copee",
"version": "1.0.0",
"description": "Copy text from browser to clipboard...natively!",
"repository": "styfle/copee",
"files": [ "dist" ],
"main": "dist/copee",
"types": "dist/copee.d.ts",
"scripts": {
"mjs": "tsc -d && mv dist/copee.js dist/copee.mjs",
"cjs": "tsc -m commonjs",
"build": "npm run mjs && npm run cjs"
},
"devDependencies": {
"typescript": "^2.5.3"
}
}
Первые четыре строки определяют пакет name
, version
, description
и GitHub repository
, которые не требуют пояснений.
Затем мы определяем files
, который мы просто определяем как одну папку dist
. Это файлы, которые будут опубликованы в npm.
Точка входа в ваш пакет определяется как main
, и именно здесь происходит волшебство. Обратите внимание, что нет расширения файла (например, .js
), как и следовало ожидать. Это позволит Node выбрать файл в зависимости от способа, которым потребитель импортирует ваш пакет - либо устаревший CJS, либо новый ESM.
Далее идет types
, который необходим для потребителей, которые хотят импортировать через TypeScript. Если вы пишете свой пакет на TypeScript, вам обязательно нужно включить types
, чтобы ваши коллеги-пользователи TS получили безопасность типов! Серьезно, это как раз то, что нужно сделать.
А теперь самое интересное: scripts
. Это ваши шаги сборки, которые можно запустить через npm run thenameofthescriptgoeshere
. На первом этапе сборки mjs
используется компилятор TypeScript (tsc
) для сборки нашего кода с использованием tsconfig.json
файла, который мы определили ранее, плюс флаг -d
, который испускает наши определения типа .d.ts
. Также обратите внимание на команду mv
, которая перемещает (или, скорее, переименовывает) выходной файл с .js
на .mjs
. Это наш вывод ESM.
Наш следующий сценарий, cjs
, использует компилятор TypeScript (tsc
) для создания того же исходного кода, но выводит результат как модуль CommonJS. Это модульная система для Node.js, которую понимают browserify
, webpack
и т. Д.
Наконец, у нас есть devDependencies
, которые являются вашими инструментами сборки. В этом случае все, что нам нужно, это typescript
, который включает команду tsc
, использованную выше.
Использование узла
Я собираюсь показать вам, как написать потребителя, который импортирует указанный выше пакет. Если вы уже регулярно используете Node, перейдите к следующему разделу об использовании ESM.
Сначала установите пакет copee:
npm install --save copee
Затем создайте index.js
файл со следующим:
const { toClipboard } = require('copee'); console.log('CJS: We found a ', typeof toClipboard);
Новую программу можно выполнить так:
node index.js
Использование узла ESM
Я собираюсь показать вам, как написать потребителя, который импортирует пакет copee, указанный выше.
После установки copee создайте index.mjs
файл. Вы должны использовать расширение сценария Майкла Джексона (.mjs).
import { toClipboard } from 'copee';
console.log('ESM: We found a ', typeof toClipboard);
Новую программу можно выполнить так:
node --experimental-modules index.mjs
Использование ESM в браузере
Использование Node не так впечатляюще, потому что с момента его создания были модули, но прелесть ESM в том, что тот же самый код, который выполняется в модуле Node, будет работать в браузере без изменений! Да, это правда! Обратите внимание на этот элегантный фрагмент кода ниже:
<script type="module"> import { toClipboard } from 'https://cdn.jsdelivr.net/npm/copee/dist/copee.mjs';
$('#btn').on('click', () => { const win = toClipboard('Wow, "copee" works!'); if (win) { // it worked, check your clipboard! } }); </script>
У нас есть новый тип сценария для module
, и мы используем jsDelivr для автоматического размещения нашего кода в CDN. Это позволяет легко написать одну строку импорта и использовать пакет copee в браузерах по всему миру!
Устаревшие браузеры
Вы скажете, что насчет устаревших браузеров? Не все поддерживают ESM? Что ж, это можно решить, связав UMD с rollup
. После установки rollup
добавьте это в раздел scripts
вашего package.json
файла.
{
"umd": "rollup -i dist/copee.mjs -o dist/copee.umd.js -f umd -n copee"
}
Вы можете без конфликтов включать сборки ESM и UMD на одну страницу. См. Фрагмент ниже:
<script nomodule src="https://cdn.jsdelivr.net/npm/copee/dist/copee.umd.js"></script> <script type="module">
import {
toClipboard
} from 'https://cdn.jsdelivr.net/npm/copee/dist/copee.mjs';
</script>
Используя атрибут nomodule
, вы указываете новым браузерам игнорировать сценарий UMD. Используя type=module
, вы говорите старым браузерам игнорировать ESM. Теперь все выигрывают!
Вы можете увидеть рабочую демонстрацию этого решения на Демонстрационной странице.
Также, пожалуйста, загляните в репозиторий GitHub для получения более подробной информации и, конечно же, рабочего исходного кода!
Первоначально опубликовано на www.ceriously.com 16 октября 2017 г.