предисловие
Ранним утром 5 октября 2019 года Юси Ю, автор Vue, опубликовал исходный код Vue3. Конечно, на данный момент это не полная версия Vue3, а предварительная альфа-версия, в которой реализованы только некоторые основные функции. гитхаб по имениvue-next, что означает следующее поколение vue. До того, как автор опубликовал статью, многие большие парни опубликовали несколько статей об интерпретации исходного кода Vue3. Тем не менее, эта статья не предназначена для добавления еще одной статьи для интерпретации исходного кода, но с точки зрения участников проекта, путем практической практики, шаг за шагом, чтобы понять и создать свой собственный проект Vue3. Поэтому для достижения наилучшего эффекта читателям рекомендуется открывать терминал во время чтения этой статьи и следовать пошаговой практике. У вас будет все, что вам нужно знать для сборки Vue3.
Перед этим рекомендуется обновить версию nodejs до v10.0 или выше.Автор проверил, что в версиях ниже v10.0 будут различные тревожные ошибки.Автор использует v10.13.0.
1. Создайте проект
1. Создайте репозиторий на гитхабе
2. Клонируйте репозиторий локально
git clone https://github.com/gtvue/vue3.git
cd vue3
git log --oneline && tree -aI .git
Вы можете видеть, что github создал для нас следующие три основных файла и сделал первоначальную отправку.
f9fa484 (HEAD -> master, origin/master, origin/HEAD) Initial commit
.
├── .gitignore
├── LICENSE
└── README.md
2. Ссылка vue-next
1. Клонировать vue-next
cd ..
git clone https://github.com/vuejs/vue-next.git
2. Просмотрите структуру каталогов vue-next.
cd vue-next
tree --dirsfirst -aI ".git*|.vscode|*.lock" -C -L 1
Разверните только каталог первого уровня, удалите файлы начала .git, .vscode и .lock, вы можете увидеть, что в основном есть 3 каталога и 8 файлов.
.
├── .circleci
├── packages
├── scripts
├── .prettierrc
├── README.md
├── api-extractor.json
├── jest.config.js
├── lerna.json
├── package.json
├── rollup.config.js
└── tsconfig.json
3 directories, 8 files
3. 3 каталога
| # | directories | what is it ? | how to use ? |
|---|---|---|---|
| 1 | .circleci | Инструменты непрерывной интеграции с облакомCircleCIкаталог конфигурации |
circleci.com |
| 2 | packages | Исходный каталог | —— |
| 3 | scripts | каталог сборки скрипта | —— |
4. 8 файлов
| # | files | what is it ? | how to use ? |
|---|---|---|---|
| 1 | .prettierrc | средство форматирования кодаprettierфайл конфигурации |
prettier.io |
| 2 | README.md | Введение в проект | —— |
| 3 | api-extractor.json | Инструмент извлечения и анализа API для TypeScriptapi-extractorфайл конфигурации |
api-extractor.com |
| 4 | jest.config.js | Фреймворк для тестирования JavaScriptjestфайл конфигурации |
jestjs.io |
| 5 | lerna.json | Многопакетный инструмент управления проектами JavaScriptlernaфайл конфигурации |
lerna.js.org |
| 6 | package.json | конфигурационный файл нпм | docs.npmjs.com |
| 7 | rollup.config.js | Сборщик модулей JavaScriptrollupфайл конфигурации |
rollupjs.org rollupjs.com |
| 8 | tsconfig.json |
TypeScriptконфигурационный файл |
tslang.cn typescriptlang.org |
5. Вернитесь к первоначальному коммиту
git checkout `git log --pretty=format:"%h" | tail -1`
git log --pretty=format:"'%an' commited at %cd : %s"
Шоу, Юси. Вы впервые представили 19 сентября 2018 г., 23:35.vue-next. Прошло уже больше года.
'Evan You' commited at Wed Sep 19 11:35:38 2018 -0400 : init (graduate from prototype)
Давайте взглянем на файлы, которые добавил Юда при первом создании проекта.
$ tree --dirsfirst -aI ".git*|.vscode|*.lock" -C -L 1
.
├── packages
├── scripts
├── .prettierrc
├── lerna.json
├── package.json
├── rollup.config.js
└── tsconfig.json
2 directories, 5 files
По сравнению с текущей структурой каталогов файлы, отправленные в первый раз, чище, в частности, отсутствуют инструменты непрерывной интеграции.CircleCI,тестовые инструментыjestи инструменты извлечения APIapi-extractor. Только исходный код и файлы, связанные со сборкой исходного кода и управлением пакетами. И это самые важные части всего проекта, здесь мы можем думать об этом как о разработке аналогичногоvue3Стартовый проект, требуемый библиотекой JavaScript. Видно, что эти документы очень важны для нас. Чтобы не «изменить историю», мы могли бы также проверить новую ветку, чтобы мы могли ее проверить.
git checkout -b InitialCommit
6. package.json
JS, чтобы понять самый важный документ, чемpackage.json, его роль эквивалентна общему замыслу всего проекта. Итак, давайте посмотрим, что было в package.json, когда You Da отправил его в первый раз.
Это кажется особенно освежающим, оно настолько простое, что в нем всего 4 поля. Нам нужно заботиться о том, чтобыscriptsа такжеdevDependencies. Скрипт сборки очень простой, за исключением привычногоdevа такжеbuildи один для форматирования всего кода TypeScript в исходном коде проекта.lint.开发依赖也是非常精简,是采用 TypeScript 开发,并用 Rollupjs 打包 Js ,最基本的依赖安装。构建脚本devа такжеbuildЭто по-прежнему способ, которым всегда стремился Юда, заключающийся в том, чтобы поместить всю логику построения в два файла js,scripts/dev.jsа такжеscripts/build.jsи использоватьnodeОбъясните исполнение. Поэтому, чтобы понять основной процесс сборки всего проекта, вам необходимо изучить реализацию этих двух файлов.
6.1 scripts/dev.js
Код для запуска режима разработки очень прост, всего 10 строк кода, фактическое использованиеexecaЗапустите исполняемый файл, установленный (node_modules) в проекте. Прототип функцииexeca(exefile, [arguments], [options]), который возвращаетPromiseобъект.
const execa = require('execa')
const { targets, fuzzyMatchTarget } = require('./utils')
const target = fuzzyMatchTarget(process.argv[2] || 'runtime-dom')
execa(
'rollup',
[
'-wc',
'--environment',
`TARGET:${target},FORMATS:umd`
],
{
stdio: 'inherit'
}
)
следовательно,node scripts/dev.jsэквивалентноpackage.jsonсередина"dev": "rollup -wc --environment TARGET:[target],FORMATS:umd", в,[target]из аргументов командыnode scripts/dev.js [target].
- -wc: комбинация -w и -c, -c с использованием файла конфигурации
rollup.config.jsПакет js , -w смотреть изменения исходного файла и автоматически переупаковывать - --environment: установить переменные среды, переданные в файл, который может находиться в файле JS, через
process.ENVЧитаем, здесь установлены две переменные окружения,process.ENV.TARGET = process.argv[2] || 'runtime-dom'а такжеprocess.ENV.FORMATS = umd
Дополнительные параметры свертки см.аргументы командной строки свертки.
6.2 scripts/build.js
Всего 70 строк кода, в целях экономии места здесь перехвачен только основной код выполнения. Это асинхронная функция немедленного вызова, которая получает командную строкуnode scripts/build.js [target]Целевой параметр (необязательный) назначается целевой переменной.Если цель не пуста, цель будет построена отдельно.Если она пуста, будут построены все цели. И так называемая цель vuepackages/подкаталогиpacakge(то же, что и имя подкаталога).
const fs = require('fs-extra')
const path = require('path')
const zlib = require('zlib')
const chalk = require('chalk')
const execa = require('execa')
const dts = require('dts-bundle')
const { targets, fuzzyMatchTarget } = require('./utils')
const target = process.argv[2]
;(async () => {
if (!target) {
await buildAll(targets)
checkAllSizes(targets)
} else {
await buildAll(fuzzyMatchTarget(target))
checkAllSizes(fuzzyMatchTarget(target))
}
})()
...
здесьbuildAll(targets)Простой цикл for:for (const target of targets) { await build(target) }.因此,构建的核心是build(target)функция.
async function build (target) {
const pkgDir = path.resolve(`packages/${target}`)
await fs.remove(`${pkgDir}/dist`)
await execa('rollup', [
'-c',
'--environment',
`NODE_ENV:production,TARGET:${target}`
], { stdio: 'inherit' })
const dtsOptions = {
name: target === 'vue' ? target : `@vue/${target}`,
main: `${pkgDir}/dist/packages/${target}/src/index.d.ts`,
out: `${pkgDir}/dist/index.d.ts`
}
dts.bundle(dtsOptions)
console.log()
console.log(chalk.blue(chalk.bold(`generated typings at ${dtsOptions.out}`)))
await fs.remove(`${pkgDir}/dist/packages`)
}
Мы обнаружили, что сборочная часть иscripts/dev.jsПоразительно похож. также использоватьexecaпередачаrollup, чуть меньше-wпараметров, то есть не нужно следить за изменениями в исходном файле. и передал переменную окруженияprocess.ENV.NODE_ENV = production, что указывает на то, что это производственная сборка.
7. rollup.config.js
Анализируя скрипт сборкиscripts/dev.jsа такжеscripts/build.js, мы знаем, что будь то сборка для разработки или производственная сборка, в конечном итоге она используетсяrollup -c rollup.config.jsспособ, используя файл конфигурацииrollup.config.jsКонфигурация для завершения сборки и упаковки JS. Сам конфигурационный файл тоже является JS-скриптом, а значит, в нем тоже может быть много кода логики, собственно, упомянутые выше переменные окруженияTARGET, FORMATS, NODE_ENV, также используется в этом файле.
if (!process.env.TARGET) {
throw new Error('TARGET package must be specified via --environment flag.')
}
// 此处省略 n 行 ...
const inlineFromats = process.env.FORMATS && process.env.FORMATS.split(',')
const packageFormats = inlineFromats || packageOptions.formats || defaultFormats
const packageConfigs = packageFormats.map(format => createConfig(configs[format]))
if (process.env.NODE_ENV === 'production') {
packageFormats.forEach(format => {
if (format === 'cjs') {
packageConfigs.push(createProductionConfig(format))
}
if (format === 'umd' || format === 'esm-browser') {
packageConfigs.push(createMinifiedConfig(format))
}
})
}
module.exports = packageConfigs
Файл конфигурации объединения может бытьESМодуль, это может бытьCommonJSмодуль, последний используется здесь. И поддерживает экспорт одного объекта конфигурации или массива объектов конфигурации, здесь экспортируется массив объектов конфигурацииpackageConfigs, что делается для одновременной упаковки нескольких модулей или пакетов.
справка по файлу конфигурации сводкиИнтерфейс командной строки свертывания - файл конфигурации.
8. TypeScript
вы можете спроситьTypeScriptГде? Фактически,TypeScriptОн используется в виде накопительного плагина. Все еще доступно в файле конфигурации накопительного пакетаrollup.config.jsСоздать функцию объекта конфигурацииcreateConfig()нашел его следы.
const ts = require('rollup-plugin-typescript2')
// 此处省略 n 行 ...
function createConfig(output, plugins = []) {
// 此处省略 n 行 ...
const tsPlugin = ts({
check: process.env.NODE_ENV === 'production' && !hasTSChecked,
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
cacheRoot: path.resolve(__dirname, 'node_modules/.rts2_cache'),
tsconfigOverride: {
compilerOptions: {
declaration: process.env.NODE_ENV === 'production' && !hasTSChecked
}
}
})
return {
plugins: [
tsPlugin,
...plugins
]
}
}
Следуя подсказкам, мы обнаружили, что плагин TypeScripttsPluginфайл конфигурации указанtsconfig.json. Итак, чтобы понять, что накопительный пакет делает с пакетом TypeScript, вы можете «пошагово»tsconfig.jsonфайл. оTypeScriptКонфигурация может относиться кtsconfig.json.
9. packages
Зная, как собирается и упаковывается проект, мы, наконец, должны поговорить о нашей цели сборки (также о цели в предыдущей статье).packages. Мы знаем, что Vue созданlernaУправлял многопакетными (npm package) проектами. Эти пакеты хранятся в каталоге пакетов, каждый пакет представляет собой подкаталог с тем же именем, что и пакет.
tree -I *.md --dirsfirst -L 2 -C packages
Запустите следующий код, чтобы попробовать производственную сборку:
npm i && npm run build
можно найти в упаковкеobserverсообщит об ошибке. Ошибка в исходном файлеpackages/observer/src/autorun.tsОпределение переменной в строке 110 файла . Будуconst runners = new Set()изменить наconst runners:Set<Autorun> = new Set(). опять такиnpm run build.
npm run build
tree -I "*.md|*.json|*.ts" --dirsfirst -L 2 -C packages
Как упоминалось в разделе 6.2 выше, при запуске без каких-либо аргументовnode scripts/build.js(npm run buildBuild scripts) соберет все пакетыpackages. Если вы упаковываете пакет отдельно, вам необходимо указать соответствующее имя пакета в качестве параметра. в корневом каталоге проектаpackage.jsonдокумент"scripts"Добавьте в поле следующее:
"build:core": "node scripts/build.js core",
"build:observer": "node scripts/build.js observer",
"build:runtime-dom": "node scripts/build.js runtime-dom",
"build:scheduler": "node scripts/build.js scheduler",
Попробуйте построить отдельно:
# 先移除已经构建的 dist 目录
rm -rf packages/*/dist
npm run build:core
npm run build:observer
npm run build:runtime-dom
npm run build:scheduler
10. lerna
Хотя много раз упоминается, что Vue используетсяlernaбольше управленияpackagesпроект. Но до сих пор, хотя мы сделали всеpackagesУпакованная сборка, до сих пор не виднаlernaиспользования. На самом деле, как мы уже говорили, lerna используется для управления несколькимиpackages, который не участвует в сборке. Лерна тоже не так сложна, как мы думали. Вот официальное введение:
Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.
Это переводится как:lernaэто инструмент оптимизации рабочего процесса для оптимизации использованияgitа такжеnpmДля управления рабочим процессом проекта с несколькими пакетами npm в одном и том же репозитории git (звучит многословно, но просто). Подразумевается, что даже если мы не используемlernaМы по-прежнему можем управлять такими репозиториями с несколькими пакетами через git и npm, но когдаpackagesвсе больше и больше, каждыйpackagesОни также зависят друг от друга, и рабочий процесс становится чрезвычайно сложным. а такжеlernaПоявление заключается в том, чтобы сделать все это и управлятьpackageТак же просто.
А теперь это, вы можете проверить это, lerna, в конце концов, привносит удобство в этот проект vue. Сначала установите глобальноlerna:
npm install --global lerna
Для использования командной строки lerna см.Официальный сайт. Вот краткая демонстрация следующих наиболее часто используемых команд (на самом деле, это практически все команды lerna).
10.1 lerna init [--independent/-i]
Используется для первой инициализации lerna в новом проекте. Он будет создан в корневом каталоге проекта.package.json , lerna.jsonфайл и пустой каталогpackages, необязательный-iили--independentИспользуется для настройки нескольких пакетов на использование отдельных версий, по умолчанию используется одна и та же версия. Конечноvue-nextуже был инициализирован, нет необходимости запускать его снова, иvue-nextиспользуя одну и ту же версию, в настоящее время обе3.0.0-alpha.1, общая версия хранится вlerna.jsonв файле.
10.2 lerna ls
Перечислите все пакеты в проекте, имена указаны под каждым пакетом.package.jsonсерединаnameполе.
$ lerna ls
info cli using local version of lerna
lerna notice cli v3.17.0
@vue/core
@vue/observer
@vue/runtime-dom
@vue/scheduler
lerna success found 4 packages
10.3 lerna bootstrap
Это самая важная команда lerna. Используется для устранения взаимозависимостей между пакетами перед публикацией в npm. Он будет основан на каждом пакете подpackage.jsonфайловые зависимости, создавать локальные ссылки на пакеты符号连接, эквивалентноnpm-linkконечно, намного проще, чем связывать локальные зависимости в каждом пакете по отдельности. Теперь все зависимости пакетов автоматически связываются одним запуском команды. Таким образом, мы можем использовать его напрямую по имени пакета, требовать или импортировать в коде каждого пакета.
lerna bootstrap
После выполнения вы можете увидеть, что в каталоге pacake другого пакета в зависимом проекте есть дополнительный каталог node_modules, в котором хранится не фактический файл пакета, а локальная символическая ссылка пакета, поэтому он также может сохранять несколько пакетов с такое же место на диске при зависимости.
10.4 lerna changed
Проверьте, какой пакет изменился с момента последней версии. Роль аналогична измерению пакетаgit-status.
10.5 lerna diff [package?]
Отображает изменения в файле с момента последней версии. Роль аналогична измерению пакетаgit-diff, это будет иgit-diffТо же самое показывает, где файл изменился. Например, в предыдущей статье мы внесли изменения в исходный код, и вы можете увидеть следующие результаты:
Конечно, мы также можем указать, чтобы видеть изменения определенного пакета, просто добавьте имя пакета после команды.Обратите внимание, что это не имя каталога, а имя пакета, определенное полем имени в package.json, например :@vue/runtime-dom. Читатели могут попробовать сами.
10.6 lerna publish
Излишне говорить, что этоnpm-publishМногопакетный дистрибутив .
3. Создайте свой собственный vue3
1. Подготовка
Мы рассмотрели поближеvue-nextпостроить проект. Затем мы можем обратиться к нему, чтобы построить собственныйvue3. Перед этим мы сначалаvue-nextизInitialCommitИзменения ветки делают фиксацию.
git add .
git commit -m "fix type error of autorun.ts and add some build scripts"
Теперь в нашем рабочем каталоге есть два проекта: vue-next и vue3. vue-next — это проект, на который мы хотим сослаться, а vue3 — это проект, который мы создали сами. Проект vue-next имеет две ветки, master и ветку InitialCommit, извлеченную из первого коммита. Конечно, InitialCommit больше не является исходной веткой. Мы успешно исправили ошибку. Хотя история была изменена, это не имеет значения. , потому что наш Он предназначен только для справки, а не для включения в оригинальную историю. Теперь мы можем произвольно переключаться между веткой master и веткой InitialCommit, чтобы обращаться к коду в разных местах по мере необходимости.
На следующих шагах мы будемvue-nextОсновная ветка для справки. Итак, сначала переключитесь на ветку master.
git checkout master
2. инициализация лерны
cd ../vue3
lerna init
лерна создается автоматическиpackage.jsonа такжеlerna.jsonДва конфигурационных файла и тот, в котором хранятся все пакеты проектаpackagesКаталог, конечно, остается пустым каталогом, в котором ничего нет.
tree -aI .git --dirsfirst -C
Отправьте один раз, прежде чем перейти к следующему шагу.
git add . && git commit -m "Add lerna for managing packages"
3. Создайте проект
Будуvue-nextСкопируйте «скрипты» в package.json в корневой каталог, чтобыvue3в package.json:
"scripts": {
"dev": "node scripts/dev.js",
"build": "node scripts/build.js",
"size-runtime": "node scripts/build.js runtime-dom -p -f esm-browser",
"size-compiler": "node scripts/build.js compiler-dom -p -f esm-browser",
"size": "yarn size-runtime && yarn size-compiler",
"lint": "prettier --write --parser typescript 'packages/**/*.ts'",
"test": "jest"
}
Установите зависимости:
yarn add -D typescript brotli chalk execa fs-extra lint-staged minimist prettier yorkie
yarn add -D rollup rollup-plugin-alias rollup-plugin-json rollup-plugin-replace rollup-plugin-terser rollup-plugin-typescript2
yarn add -D jest ts-jest @types/jest
Скопируйте весь каталог сборки скриптов:
cd .. && cp -r vue-next/scripts vue3
Скопируйте файл конфигурации:
cp vue-next/{rollup.config.js,tsconfig.json,jest.config.js,.prettierrc} vue3
4. Скопируйте последний исходный код
cp -r vue-next/packages/* vue3/packages
5. Последний исходный пакет
$ cd vue3 && lerna ls
lerna notice cli v3.16.5
@vue/compiler-core
@vue/compiler-dom
@vue/reactivity
@vue/runtime-core
@vue/runtime-dom
@vue/runtime-test
@vue/server-renderer
vue
lerna success found 8 packages
$ tree -I "*.ts" -L 1 -C packages
packages
├── compiler-core
├── compiler-dom
├── reactivity
├── runtime-core
├── runtime-dom
├── runtime-test
├── server-renderer
├── shared
├── template-explorer
└── vue
10 directories, 0 files
Вы можете видеть, что есть 10 каталогов, но только 8 пакетов. Это связано с тем, что lerna распознает пакет только как каталог, содержащий файл package.json, а поле «private» не равно True, что также требуется для npm. Восемь каталогов и соответствующие имена пакетов следующие:
| содержание | package |
|---|---|
| compiler-core | @vue/compiler-core |
| compiler-dom | @vue/compiler-dom |
| reactivity | @vue/reactivity |
| runtime-core | @vue/runtime-core |
| runtime-dom | @vue/runtime-dom |
| runtime-test | @vue/runtime-test |
| server-renderer | @vue/server-renderer |
| vue | vue |
6. Создайте тест
Создайте SymLink на локальные пакеты:
# rm -rf packages/*/{dist,node_modules}
lerna bootstrap
Запустить режим разработки:
yarn dev
Собрать все пакеты:
yarn build
# tree -I "*.md|*.json|*.ts|__tests__|node_modules|*.html|*.js|*.css" --dirsfirst -L 2 -C packages
Проверьте размер файла пакета:
yarn size-runtime
yarn size-compiler
yarn size
Проверка спецификации кода:
yarn lint
тестовое задание:
yarn test
отлично!Все прошло хорошо.
7. Отправить
git add .
git commit -m "Start vue3"
The End
Поздравляем! Теперь у вас есть собственный проект Vue3. Продолжайте вносить свой собственный код Vue3, хорошая новость заключается в том, что вы можете продолжать следить за особенно большим прогрессом и плавно «ссылаться» на последний код, чтобы усовершенствовать свой проект.
Адрес исходного кода этой статьи:github.com/gtvue/vue3
Thank you
Написание этой статьи отняло у автора много сил. Если эта статья поможет вам что-то получить, пожалуйста, не стесняйтесь ставить лайк 👍
Отсканируйте QR-код в WeChat, чтобы получить оригиналы новейших технологий