Skip to content

Обновление гайда NuxtJS + FSD #798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,173 +7,250 @@ sidebar_position: 10

- Изначально, NuxtJS предлагает файловую структуру проекта без папки `src`, то есть в корне проекта.
- Файловый роутинг находится в папке `pages`, а в FSD эта папка отведена под плоскую структуру слайсов.
- Автоимпорты работают для всех компонентов, в то время как FSD пропагандирует концепцию Public API (делится только необходимым из index файлов).

Но NuxtJS обладает довольно гибкой настройкой конфигурации, что поможет нам полноценно внедрить в него FSD, не теряя его основных достоинств со стороны разработки:

## Добавление алиаса для `src` директории
- Автоимпорты.
- Файловый роутинг.

Добавьте обьект `alias` в ваш конфиг:
```ts title="nuxt.config.ts"
export default defineNuxtConfig({
devtools: { enabled: true }, // Не относятся к FSD, включёны при старте проекта
alias: {
"@": '../src'
},
})
```
## Выбор способа настройки роутера
## Автоимпорты

В NuxtJS есть два способа настройки роутинга - с помощью конфига и с помощью файловой структуры.
В случае с файловым роутингом вы будете создавать index.vue файлы в папках внутри директории app/routes, а в случае конфига - настраивать роуты в `router.options.ts` файле.
На первый взгляд автоимпорты противоречат концепции Public Api и FSD, т.к. создает импорты для всех компонентов, но этого можно избежать, правильно настроив конфигурацию.

### Компоненты

### Роутинг с помощью конфига
По умолчанию в NuxtJS для компонентов выделена дирректория `components/`.

В слое `app` создайте файл `router.options.ts`, и экспортируйте из него обьект конфига:
```ts title="app/router.options.ts"
import type { RouterConfig } from '@nuxt/schema';
Дирректории для компонентов можно переопределить настройкой `components`.

export default <RouterConfig> {
routes: (_routes) => [],
};
#### shared

```ts
components: {
dirs: [
{
path: "~/src/shared", // shared дирректория
pattern: "**/*index.vue", // Файл для автоимпорта
extensions: ["vue"],
},
];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
];
],

}
```

Чтобы добавить страницу `Home` в проект, вам нужно сделать следующие шаги:
- Добавить слайс страницы внутри слоя `pages`
- Добавить соответствующий роут в конфиг `app/router.config.ts`
#### entities

```ts
components: {
dirs: [
{
path: "~/src/entities", // entities дирректория
extendComponent(component) {
component.pascalName = component.pascalName.replaceAll("Ui", ""); // Убираем Ui дирректории из имени компонента
return component;
},
pattern: "**/*index.vue", // Файл для автоимпорта
extensions: ["vue"],
},
];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
];
],

}
```

Для того чтобы создать слайс страницы, воспользуемся [CLI](https://github.com/feature-sliced/cli):
#### features

```shell
fsd pages home
```ts
components: {
dirs: [
{
path: "~/src/features", // features дирректория
extendComponent(component) {
component.pascalName = component.pascalName.replaceAll("Ui", ""); // Убираем Ui дирректории из имени компонента
component.pascalName = component.pascalName + "Feature"; // Добавляем Feature постфикс
return component;
},
pattern: "**/*index.vue", // Файл для автоимпорта
extensions: ["vue"],
},
];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
];
],

}
```

Создайте файл `home-page.vue` внутри сегмента ui, откройте к нему доступ с помощью Public API
#### widgets

```ts title="src/pages/home/index.ts"
export { default as HomePage } from './ui/home-page';
```ts
components: {
dirs: [
{
path: "~/src/widgets", // widgets дирректория
extendComponent(component) {
component.pascalName = component.pascalName.replaceAll("Ui", ""); // Убираем Ui дирректории из имени компонента
component.pascalName = component.pascalName + "Widget"; // Добавляем Widget постфикс
return component;
},
pattern: "**/*index.vue", // Файл для автоимпорта
extensions: ["vue"],
},
];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
];
],

}
```

Таким образом, файловая структура будет выглядеть так:
```sh
|── src
│ ├── app
│ │ ├── router.config.ts
│ ├── pages
│ │ ├── home
│ │ │ ├── ui
│ │ │ │ ├── home-page.vue
│ │ │ ├── index.ts
#### pages

```ts
components: {
dirs: [
{
path: "~/src/pages", // pages дирректория
pattern: "**/*index.vue", // Файл для автоимпорта
extensions: ["vue"],
},
];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
];
],

}
```
Наконец, добавим роут в конфиг:

```ts title="app/router.config.ts"
import type { RouterConfig } from '@nuxt/schema'
### Типы, функции и т.п.

export default <RouterConfig> {
routes: (_routes) => [
{
name: 'home',
path: '/',
component: () => import('@/pages/home.vue').then(r => r.default || r)
}
По умолчанию в NuxtJS для этого выделена дирректория `utils/` и т.п.

Такие дирректории можно переопределить настройкой `imports`.

```ts
imports: {
dirs: [
"./src/widgets/*/*/index.ts", // Автоимпорты для widgets слоя
"./src/features/*/*/index.ts", // Автоимпорты для features слоя
"./src/entities/*/*/index.ts", // Автоимпорты для entities слоя
"./src/shared/*/index.ts", // Автоимпорты для shared слоя
],
}
```

### Файловый роутинг
### Использование

В первую очередь, создайте `src` директорию в корне проекта, а также создайте внутри этой директории слои app и pages и папку routes внутри слоя app.
Таким образом, ваша файловая структура должна выглядеть так:
1. Создайте `src` дирректорию.
2. Добавьте в `src` дирректорию FSD слои.

```sh
├── src
│ ├── app
│ │ ├── routes
│ ├── pages # Папка pages, закреплённая за FSD
```bash
.../
├── src/
│ ├── app/
│ ├── entities/
│ ├── features/
│ ├── shared/
│ ├── widgets/
```

Для того чтобы NuxtJS использовал папку routes внутри слоя `app` для файлового роутинга, вам нужно изменить `nuxt.config.ts` следующим образом:
```ts title="nuxt.config.ts"
export default defineNuxtConfig({
devtools: { enabled: true }, // Не относятся к FSD, включёны при старте проекта
alias: {
"@": '../src'
},
dir: {
pages: './src/app/routes'
}
})
#### shared

Рассмотрим компонент `UiButton` для примера.

##### Структурв папок

```bash
.../
├── src/
│ ├── shared/
│ │ ├── ui/
│ │ │ ├── button/
│ │ │ │ ├── interfaces/
│ │ │ │ │ ├── ...
│ │ │ │ ├── index.ts # Для автоимпортов типов компонента
│ │ │ │ ├── index.vue # Для автоимпорта компонента
│ │ ├── utils/ # Любой сегмент
│ │ │ ├── sum.ts
│ │ │ ├── index.ts # Для автоимпорта функции и т.п. сегмента
```

Теперь, вы можете создавать роуты для страниц внутри `app` и подключать к ним страницы из `pages`.
`ui/button/index.ts` - файл для автоимпорта типов компонента.

Например, чтобы добавить страницу `Home` в проект, вам нужно сделать следующие шаги:
- Добавить слайс страницы внутри слоя `pages`
- Добавить соответствующий роут внутрь слоя `app`
- Совместить страницу из слайса с роутом
```ts
export type { IUiButtonProps } from "./interfaces";
```

Для того чтобы создать слайс страницы, воспользуемся [CLI](https://github.com/feature-sliced/cli):
`ui/button/index.vue` - файл для автоимпорта компонента.

```shell
fsd pages home
```
```vue
<script setup lang="ts">
import type { IUiButtonProps } from "./interfaces";

Создайте файл `home-page.vue` внутри сегмента ui, откройте к нему доступ с помощью Public API
const props = withDefaults(defineProps<IUiButtonProps>(), {
type: "button",
});
</script>

```ts title="src/pages/home/index.ts"
export { default as HomePage } from './ui/home-page';
<template>
<button :type="type">
<slot />
</button>
</template>
```

Создайте роут для этой страницы внутри слоя `app`:
`utils/index.ts` - файл для автоимпорта функции и т.п. сегмента.

```sh

├── src
│ ├── app
│ │ ├── routes
│ │ │ ├── index.vue
│ ├── pages
│ │ ├── home
│ │ │ ├── ui
│ │ │ │ ├── home-page.vue
│ │ │ ├── index.ts
```ts
export { sum } from "./sum";
```

Добавьте внутрь `index.vue` файла компонент вашей страницы:
##### Использование

```html title="src/app/routes/index.vue"
<script setup>
import { HomePage } from '@/pages/home';
```vue
<script setup lang="ts">
const props: IUiButtonProps = {
type: "submit",
};
</script>

<template>
<HomePage/>
<UiButton v-bind="props"> Total: {{ sum(1, 4) }} </UiButton>
</template>
```

## Что делать с `layouts`?

Вы можете разместить layouts внутри слоя `app`, для этого нужно изменить конфиг следующим образом:

```ts title="nuxt.config.ts"
export default defineNuxtConfig({
devtools: { enabled: true }, // Не относятся к FSD, включёны при старте проекта
alias: {
"@": '../src'
},
dir: {
pages: './src/app/routes',
layouts: './src/app/layouts'
}
})
#### entities

Все также, как с `shared`, но компоненты не имеют `Ui` префикса и в структуру папок добавляется папка `слайса`.

#### features, widgets

Все также, как с `entities`, но компоненты имеют `Feature` и `Widget` постфикс.

#### pages

```bash
.../
├── src/
│ ├── pages/
│ │ ├── product/ # Любая страница
│ │ │ ├── index.vue # Для автоимпорта компонента страницы
```

## Роутинг, шаблоны, middleware

Необходимо переопределить дирректории по умолчанию.

```ts
dir: {
pages: "./src/app/routes", // Роутинг
layouts: "./src/app/layouts", // Шаблоны
middleware: "./src/app/middlewares", // middlewares
},
```

### app

```bash
.../
├── src/
│ ├── app/
│ │ ├── routes/ # Роуты приложения
│ │ │ ├── index.vue # Роут для пути "/"
│ │ ├── middlewares/ # Middleware приложения
│ │ │ ├── auth.ts # Middleware авторизации
│ │ ├── layouts/ # Шаблоны приложения
│ │ │ ├── default.vue # Шаблон приложения по умолчанию
```

## См. также
## Хочешь начать быстрее

- [Документация по изменению конфига директорий в NuxtJS](https://nuxt.com/docs/api/nuxt-config#dir)
- [Документация по изменению конфига роутера в NuxtJS](https://nuxt.com/docs/guide/recipes/custom-routing#router-config)
- [Документация по изменению алиасов в NuxtJS](https://nuxt.com/docs/api/nuxt-config#alias)
Чтобы не настраивать все вручную, можно использовать модуль, который автоматически меняет конфигурацию.

[@dand.dev/nuxt-fsd](https://www.npmjs.com/package/@dand.dev/nuxt-fsd)
Loading