[doc]: Добавить возможность копипаста реализации хуков из доки
Иногда не хочется тянуть отдельный пакет с хуками ради одного или двух хуков. Многие хуки вполне самодостаточны и их можно запихнуть в 1-2 небольших файла. А значит можно сделать реализацию на подобие shadcn/ui, где есть "ручная(manual)" установка. И нужно только скопировать код и вставить. Ну и установить что-то сторонние, если в хуке такое нужно. Хотя это определённо снизит количество скачиваний npm пакета((
https://github.com/novajslabs/cli/blob/main/src/commands/add.ts cli можно добавиь на ряду с этим, вообще я считаю, что это уже золотой стандарт
- [ ] cli
- [ ] транспиляция из ts в js для cli
Попробую сделать.
@zeroqs хорошо, сразу скажу пару вводных, в mock-config-server есть схожее и это очень легко сделать на самом деле
- Надо научиться превращать ts в читаймый js
- Надо создать папку bin и в ней реализовать скрипт похожий https://github.com/novajslabs/cli/blob/main/src/commands/add.ts
@zeroqs хорошо, сразу скажу пару вводных, в mock-config-server есть схожее и это очень легко сделать на самом деле
- Надо научиться превращать ts в читаймый js
- Надо создать папку bin и в ней реализовать скрипт похожий https://github.com/novajslabs/cli/blob/main/src/commands/add.ts
Вот либы https://github.com/elyx-code/typescript-to-js https://github.com/ritz078/transform/tree/master ( Web - https://transform.tools/typescript-to-javascript )
https://github.com/jerosoler/ts2js - вроде прикольно но юзает monaco-editor ( https://www.npmjs.com/package/monaco-editor ) не знаю на сколько ок его сюда тащить
Но как я понял без babel никак, но он оч сильно раздует бандл ( Тогда можно вынести в отдельный "пакет" как в shadcn - https://github.com/shadcn-ui/ui/tree/main/packages)
И еще момент со сборкой, если я помещу папку bin на один и тот же уровень с папкой src, то он не окажется в сборке, как фиксануть ?
Просто щас я создал ее внутри src и получается cli есть и на cjs и на esm модулях, хотя я думаю это не оч правильно. Постарался в конфиг роллапа, зашел в core пакет увидел что output опций только два как раз на cjs и esm
На счет сборки, можно вынести в отдельный "пакет" как в shadcn - https://github.com/shadcn-ui/ui/tree/main/packages
Просто я сейчас захотел использовать ora - https://www.npmjs.com/package/ora, а там падает ошибка когда я использую spinner - ReferenceError: navigator is not defined, ну я вроде понял почему, но не уверен.
UPD:
Сделал в отдельной директории и думаю проблем с babel не будет уже, сделал в отдельном потому что если делать в основном то будут тянутся не нужные зависимости если юзер скачает хуки npm пакетом
Осталось проблема в скачивании хука если он имеет зависимость от импортируемого типа или чего либо еще.
Я пока додумался только на проверку присутствует ли импорт который начинается с @/ и если да то скачивать его тоже
И я не совсем понимаю cli это минимальный вариант, а в самой доке реализация для копипаста, это идеал или наоборот?))
А почему нельзя бабелем транспиляцию сделать? Вроде должно остаться читабельным. Что-то типо этого использовать в конфиге:
"presets": [
"@babel/preset-typescript",
["@babel/preset-env", { "targets": { "node": "current" } }]
]
А синтаксис подсвечивать легкой https://prismjs.com/ (в doka используется она, других не знаю))) В shadcn кстати вообще только ts
@debabin
Вообщем-с апдейт по cli
Эта версия написана с использованием API гитхаба в следствие чего есть лимит по использованию. Я решил пойти и узнать как там в shadcn это сделано ( фетч хука, как ? откуда ? и тп )
Как это в shadcn ?
Есть такой основной реестр который формируется скриптом отсюда
import { registry } from "../registry"
const result = registrySchema.safeParse(registry)
await buildRegistry(result.data)
Импорт под-реестра который формирует основной реестр вот тут, нам ток ui интересен
import { ui } from "@/registry/registry-ui"
export const registry = {
name: "shadcn/ui",
homepage: "https://ui.shadcn.com",
items: [
...ui,
...blocks,
...charts,
...lib,
...hooks,
...themes,
// Internal use only.
...internal,
...examples,
],
}
Ну и вот он и получается он в ручную описан ? ( Я вот этого не понял )
Дальше имеем вот такой json реестра который хостится тут - https://ui.shadcn.com/registry/index.json и к которому делают запросы при добавлении компонента ( там происходит анализ нужен ли компоненту другой компонент, и тп )
registryIndex = await getRegistryIndex()
вот тут get реестра getRegistryIndex()
вот тут фетч реестра fetchRegistry()
const baseUrl = process.env.COMPONENTS_REGISTRY_URL ?? "https://ui.shadcn.com"
const registryIndex = await getRegistryIndex()
export async function getRegistryIndex() {
try {
const [result] = await fetchRegistry(["index.json"])
return registryIndexSchema.parse(result)
} catch (error) {
throw new Error(`Failed to fetch components from registry.`)
}
}
async function fetchRegistry(paths: string[]) {
try {
const results = await Promise.all(
paths.map(async (path) => {
const response = await fetch(`${baseUrl}/registry/${path}`, {
agent,
})
return await response.json()
})
)
return results
} catch (error) {
console.log(error)
throw new Error(`Failed to fetch registry from ${baseUrl}.`)
}
}
Что придумал сделать
Сделать скрипт формирование реестра который будет в себя включать 1 запрос на весь список хуков потом они будут записаны в реестр с их зависимостями что то типо такого и потом при добавлении хука командой add будет фетч в наш реестр хуков и получается скачивание хука, если есть зависимости то скачать их тоже.
Может возникнуть вопрос что за localDependency, я так обозначил вот например как тут я про constants, но возник вопрос нужны ли нам localDependency потому что я посмотрел и эти constants нужны для демки, вообщем имеет ли смысл localDependency
Вопрос Как анализировать использует ли хук другие хуки или функции из utils ? Я додумался только до регулярки
const registry = [
{
name: hookName,
localDependency: [],
hookDependency: [],
utilsDependency: []
},
...
]
И будет что то типо
const registry = [
{
name: useActiveElement,
localDependency: [],
hookDependency: ["useMutationObserver"],
utilsDependency: []
},
{
name: useDebounceCallback,
localDependency: [],
hookDependency: ["useEvent"],
utilsDependency: ["debounce "]
},
...
]
А как я буду качать хуки?
Вот так - https://raw.githubusercontent.com/siberiacancode/reactuse/main/src/hooks/useAsync/useAsync.ts
Ну то есть проходится по всему реестру и просто качать + анализировать если ли зависимости и если есть качать их тоже
Вроде как ничего не упустил, было сложно так как вообще первый раз занимаюсь прям таким изучением чужих исходников ( я про опен сорс и либы в частности ) но интересно, вот вообщем все, что думаешь ?
Надеюсь ничего не упустил 👉👈
UPD: raw.githubusercontent.com - Ограна по api не имеет потому что это не апишка ( удивительно :) ), но тк это запрос к статическому файлу, то там могут быть свои ограны, так что надо будет наверное все таки качать себе на сервак или чет такое
Также вместо регулярок для поиска импорта можно использовать acorn с плагином для поддержки ts Вот репка я уже начал - https://github.com/zeroqs/hook-imports-analyzer
Импорт под-реестра который формирует основной реестр вот тут, нам ток ui интересен
А почему нам интересен только ui? Там вроде хуки тоже есть. (или я затупил и это про названия их репозитория?)))
Как анализировать использует ли хук другие хуки или функции из utils ? Я додумался только до регулярки
А типы будут учитываться как локальные зависимоти, да? useParallax
Надеюсь ничего не упустил 👉👈
А что по поводу конфигурации у пользователя. Куда будем устанавливать и что уже установленно из зависимостей. Я так понимаю нужен какой-то аналог "components.json" вот такой только видимо reactuse.json (для универсальности лучше, чем просто hooks.json) А также возможно стоит предусмотреть флаг изменения имени хука в cli команде для установки. (Ну мало ли, вдруг мне нужно две разных реализации одного хука или какой-нибудь shadcn использует свой хук, а с новым хуком он сломается)
так что надо будет наверное все таки качать себе на сервак
Ну и статискику использования можно будет собирать) Или она и так как-то будет учитываться при использовании cli?
@debabin наверно можно закрывать