Создание сайтов в Моспино, ДНР. Как создать монорепозиторий с помощью Nx, Next.js и TypeScript

 
 

В этой статье мы узнаем, что такое монорепозиторий и как монорепозитории помогают быстрее разрабатывать приложения с лучшим опытом разработки. Мы обсудим преимущества использования инструментов разработки Nx для управления монорепозиторием и узнаем, как использовать эти инструменты для создания приложения Next.js.

Код для этой статьи доступен на GitHub. Вы можете найти рабочую демонстрацию приложения, которое мы создаем, здесь.

Что такое монорепозиторий и почему мы должны рассмотреть возможность его использования

Монорепозиторий — это единый репозиторий, содержащий приложения, инструменты и конфигурации нескольких проектов или компонентов проекта. Это альтернатива созданию отдельных репозиториев для каждого проекта или части проекта.

Рассмотрим сценарий, в котором мы создаем приложение панели мониторинга с использованием некоторой внешней библиотеки или фреймворка. Код для этого внешнего приложения может храниться в dashboardрепозитории. Компоненты пользовательского интерфейса, которые использует этот репозиторий, могут храниться в другом репозитории с именем components. Теперь каждый раз, когда мы обновляем componentsрепозиторий, нам нужно заходить в dashboardрепозиторий и обновлять componentsзависимость.

Два репозитория — дашборд и компоненты

Чтобы решить эту проблему, мы могли бы объединить componentsрепо с dashboardрепо.

Репозиторий компонентов объединен с репозиторием панели инструментов

Однако может существовать другое клиентское приложение для маркетингового сайта, которое хранится в marketingрепозитории и зависит от componentsрепозитория. Итак, нам придется продублировать componentsи объединить его marketing. Однако из-за этого любое изменение, связанное с components, должно быть сделано в двух местах, что не идеально.

Панель инструментов и маркетинговые репозитории, каждый с копией компонентов

Вышеупомянутую проблему можно решить с помощью монорепозитория, в котором dashboardкомпоненты componentsи marketingнаходятся в одном репозитории.

Монорепозиторий, содержащий информационную панель, маркетинг и компоненты

Существуют различные преимущества использования монорепозитория:

Обновление пакетов намного проще, так как все приложения и библиотеки находятся внутри единого репозитория. Поскольку все приложения и пакеты находятся в одном репозитории, добавление нового кода или изменение существующего кода можно легко протестировать и отправить.

Рефакторинг кода намного проще, так как нам нужно будет делать это только в одном месте, а не копировать один и тот же материал в нескольких репозиториях.

Монорепозиторий обеспечивает согласованную конфигурацию конвейеров CI/CD, которую можно повторно использовать всеми приложениями и библиотеками, присутствующими в одном репозитории.

Публикация пакетов также становится намного проще благодаря таким инструментам, как Nx.

Nx CLI поможет нам в создании новых приложений Next.js и библиотек компонентов React. Это также поможет нам запустить веб-сервер разработки с горячей перезагрузкой модулей. Он также может выполнять множество других важных вещей, таких как линтинг, форматирование и генерация кода. Преимущество использования такого CLI в том, что он обеспечивает чувство стандартизации в нашей кодовой базе. По мере того, как наша кодовая база растет, очень сложно управлять и понимать лежащие в ее основе сложности. Nx CLI устраняет большинство этих сложностей, предоставляя инструменты для автоматизации генерации кода.

Требуется программное обеспечение

Для запуска нашего приложения нам потребуется следующее:

над уровнем моря

Пряжа (по желанию)

В приложении будут использоваться следующие технологии:

Next.js для создания нашего приложения

Styled Components для добавления стилей в наше приложение

Примечание: вы можете прочитать больше о том, как установить несколько версий Node.js с помощью nvm, если хотите ускориться.

Нам также понадобится учетная запись Product Hunt.

Установка и загрузка рабочей области Nx

Мы можем установить Nx CLI, используя следующую команду:

npm install nx -g

Приведенная выше команда установит Nx CLI глобально. Это полезно, потому что теперь мы можем создать новое приложение Next.js, используя этот CLI, из любого каталога.

Затем нам нужно запустить следующую команду в каталоге, где мы хотим создать наш монорепозиторий:

npx create-nx-workspace@latest nx-nextjs-monorepo

Создать рабочее пространство

Шаг 2: Он спросит у нас имя приложения, которое мы хотим создать. Мы можем назвать это как угодно. В этом случае мы назовем его «охота за продуктом».

Введите название приложения

Шаг 3: Он спросит нас, какой тип таблицы стилей мы хотим использовать. Мы выберем Styled Components.

Введите формат таблицы стилей по умолчанию

Шаг 4: Нас спросят, хотим ли мы использовать Nx Cloud, платформу для ускорения сборки приложений Nx. В этом случае мы выберем Нет, но, пожалуйста, проверьте это.

Используете Nx Cloud?

Теперь Nx создаст все файлы и каталоги и сгенерирует для нас следующую структуру.

Структура каталогов

Каталог appsсодержит все наши приложения. В нашем случае этот каталог будет содержать приложение Next.js, которое мы создаем (с именем product-hunt). Этот каталог также содержит сквозные тестовые приложения (с именем product-hunt-e2e), созданные с помощью Cypress.

Каталог libsсодержит все библиотеки, такие как компоненты, служебные функции и т. д. Эти библиотеки могут использоваться любым из приложений, присутствующих в appsкаталоге.

Каталог toolsсодержит все пользовательские скрипты, кодмоды и т. д., которые используются для внесения определенных изменений в нашу кодовую базу.

Примечание: больше информации о структуре каталогов доступно здесь.

Создание главной страницы Product Hunt с помощью Next.js

На этом этапе мы создадим главную страницу Producthunt. Мы будем получать данные из официального API Product Hunt. API Product Hunt предоставляет интерфейс GraphQL, который доступен по адресу https://api.producthunt.com/v2/api/graphql. Доступ к нему можно получить с помощью access_token, который можно сгенерировать на панели инструментов API Product Hunt.

Чтобы создать новое приложение, нам нужно нажать на кнопку ДОБАВИТЬ ПРИЛОЖЕНИЕ.

Добавить приложение

Затем мы можем добавить имя для нашего приложения и https: //localhost:4200/ в качестве URI перенаправления для нашего нового приложения и нажать кнопку «Создать приложение «.

Создать приложение

Теперь мы сможем просмотреть учетные данные нашего нового приложения.

Новые учетные данные приложения

Далее нам нужно сгенерировать токен разработчика, нажав кнопку CREATE TOKEN на той же странице.

Создать токен разработчика

Это создаст новый токен и отобразит его на странице.

Показать токен разработчика

Далее нам нужно сохранить эти учетные данные внутри нашего приложения. Мы можем создать новый.env.localфайл внутри apps/product-huntкаталога со следующим содержимым:

// apps/product-hunt/.env.local

NEXT_PUBLIC_PH_API_ENDPOINT=https: //api.producthunt.com/v2/api/graphql

NEXT_PUBLIC_PH_TOKEN=<your-developer-token>

Поскольку API Product Hunt находится в GraphQL, нам нужно будет установить несколько пакетов, чтобы наше приложение работало с GraphQL. Из корневого каталога нам нужно запустить следующую команду для установки необходимых пакетов:

yarn add graphql-hooksgraphql-hooks-memcache

graphql-hooks — это клиент GraphQL с минимальными хуками. Это помогает нам запрашивать данные с сервера GraphQL.

graphql-hooks-memcache — это реализация кэширования в памяти для graphql-hooks.

Далее нам нужно инициализировать клиент GraphQL из graphql-hooksпакета. Мы можем сделать это, создав новый graphql-client.tsфайл внутри apps/product-hunt/libкаталога со следующим содержимым:

// apps/product-hunt/lib/graphql-client.ts

import { GraphQLClient } from „graphql-hooks“;

import memCache from „graphql-hooks-memcache“;

import { useMemo } from „react“;

let graphQLClient;

const createClient = (initialState) => {

return new GraphQLClient ({

ssrMode: typeof window === „undefined“,

url: process.env.NEXT_PUBLIC_PH_API_ENDPOINT, // Server URL (must be absolute)

cache: memCache ({ initialState }),

headers: {

Authorization: `Bearer ${process.env.NEXT_PUBLIC_PH_TOKEN}`,

},

}) ;

};

export const initializeGraphQL = (initialState = null) => {

const _graphQLClient = graphQLClient?? createClient (initialState) ;

// After navigating to a page with an initial GraphQL state, create a new

// cache with the current state merged with the incoming state and set it to

// the GraphQL client. This is necessary because the initial state of

// `memCache` can only be set once

if (initialState && graphQLClient) {

graphQLClient.cache = memCache ({

initialState: Object.assign (

graphQLClient.cache.getInitialState (),

initialState

),

}) ;

}

// For SSG and SSR always create a new GraphQL Client

if (typeof window === „undefined“) {

return _graphQLClient;

}

// Create the GraphQL Client once in the client

if (! graphQLClient) {

graphQLClient = _graphQLClient;

}

return _graphQLClient;

};

export const useGraphQLClient = (initialState) => {

const store = useMemo (() => initializeGraphQL (initialState), [initialState]) ;

return store;

};

Приведенный выше код аналогичен официальному примеру Next.js GraphQL. Основная идея приведенного выше файла заключается в создании клиента GraphQL, который поможет нам запрашивать данные с сервера GraphQL.

Функция createClientотвечает за создание клиента GraphQL с помощью graphql-hooksпакета.

Эта initializeGraphQLфункция отвечает за инициализацию нашего клиента GraphQL, createClientа также за гидратацию нашего клиента GraphQL на стороне клиента. Это необходимо, потому что мы используем Next.js, который позволяет нам получать данные как на стороне клиента, так и на стороне сервера. Таким образом, если данные извлекаются на стороне сервера, клиентскую сторону также необходимо заполнить теми же данными без выполнения каких-либо дополнительных запросов к серверу GraphQL.

Это useGraphQLClientхук, который можно использовать для создания клиента GraphQL.

Далее нам также нужно создать еще один файл graphql-request.tsвнутри apps/product-hunt/libкаталога со следующим содержимым:

// apps/product-hunt/lib/graphql-request.ts

const defaultOpts = {

useCache: true,

};

// Returns the result of a GraphQL query. It also adds the result to the

// cache of the GraphQL client for better initial data population in pages.

// Note: This helper tries to imitate what the query hooks of `graphql-hooks`

// do internally to make sure we generate the same cache key

const graphQLRequest = async (client, query, options = defaultOpts) => {

const operation = {

query,

};

const cacheKey = client.getCacheKey (operation, options) ;

const cacheValue = await client.request (operation, options) ;

client.saveCache (cacheKey, cacheValue) ;

return cacheValue;

};

export default graphQLRequest;

Функция graphQLRequestотвечает за возврат результата запроса GraphQL, а также за добавление результата в кеш клиента GraphQL.

Приведенный выше код аналогичен официальному примеру Next.js GraphQL.

Далее нам нужно обновить apps/product-hunt/pages/_app.tsxфайл со следующим содержимым:

// apps/product-hunt/pages/_app.tsx

import { ClientContext } from „graphql-hooks“;

import { AppProps } from „next/app“;

import Head from „next/head“;

import React from „react“;

import { useGraphQLClient } from „.../lib/graphql-client“;

const NextApp = ({ Component, pageProps }: AppProps) => {

const graphQLClient = useGraphQLClient (pageProps.initialGraphQLState) ;

return (

 

 

 

 

) ;

};

export default NextApp;

Приведенный выше код гарантирует, что все наше приложение имеет доступ к поставщику контекста GraphQL, обернув наше приложение с помощью файла ClientContext.Provider.

Далее нам нужно создать еще один файл all-posts.tsвнутри apps/product-hunt/queriesкаталога со следующим содержимым:

// apps/product-hunt/queries/all-posts.ts

const ALL_POSTS_QUERY = `

query allPosts {

posts {

edges {

node {

id

name

description

votesCount

website

thumbnail {

url

}

}

}

}

}

`;

export default ALL_POSTS_QUERY;

Приведенный выше запрос GraphQL позволит нам получить все сообщения из конечной точки ProductHunt GraphQL API.

Давайте также создадим новый product.tsфайл внутри apps/product-hunt/typesкаталога со следующим содержимым, чтобы определить Productтип:

// apps/product-hunt/types/product.ts

export default interface Product {

id: number;

name: string;

tagline: string;

slug: string;

thumbnail: {

image_url: string;

};

user: {

avatar_url: string;

name: string;

};

}

Приведенный выше код добавляет типы TypeScript для Product. Продукт может иметь идентификатор, имя, слоган, ярлык, миниатюру и пользователя. Вот как Product Hunt GraphQL возвращает данные.

Далее нам нужно обновить apps/product-hunt/pages/index.tsxфайл со следующим содержимым:

// apps/product-hunt/pages/index.tsx

import { useQuery } from „graphql-hooks“;

import { GetStaticProps, NextPage } from „next“;

import Image from „next/image“;

import React from „react“;

import { initializeGraphQL } from „.../lib/graphql-client“;

import graphQLRequest from „.../lib/graphql-request“;

import {

StyledCard,

StyledCardColumn,

StyledCardLink,

StyledCardRow,

StyledCardTagline,

StyledCardThumbnailContainer,

StyledCardTitle,

StyledContainer,

StyledGrid,

} from „.../public/styles“;

import ALL_POSTS_QUERY from „.../queries/all-posts“;

import Product from „.../types/product“;

interface IProps {

hits: Product[];

}

const ProductsIndexPage: NextPage = () => {

const { data } = useQuery (ALL_POSTS_QUERY) ;

return (

{data.posts.edges.map (({ node }) => {

return (

 

 

 

{node.name}

{node.description}

 

 

 

 

) ;

}) }

 

 

) ;

};

export const getStaticProps: GetStaticProps = async () => {

const client = initializeGraphQL () ;

await graphQLRequest (client, ALL_POSTS_QUERY) ;

return {

props: {

initialGraphQLState: client.cache.getInitialState (),

},

revalidate: 60,

};

};

export default ProductsIndexPage;

В приведенном выше фрагменте кода мы делаем две вещи:

Мы извлекаем данные с помощью ALL_POSTS_QUERYзапроса GraphQL, а затем сопоставляем dataмассив, возвращаемый API ProductHunt.

Мы извлекаем данные во время сборки через getStaticProps, который является функцией Next.js. Однако, если мы получим данные во время сборки, они могут устареть. Итак, используем revalidateвариант. Повторная проверка необязательного количества (в секундах), после которого может произойти повторное создание страницы. Это также известно как добавочная статическая регенерация.

Давайте также добавим стили, добавив в apps/product-hunt/public/styles.tsфайл следующее содержимое:

// apps/product-hunt/public/styles.ts

import styled from „styled-components“;

export const StyledContainer = styled.div`

padding: 24px;

max-width: 600px;

margin: 0 auto;

font-family: sans-serif;

`;

export const StyledGrid = styled.div`

display: grid;

grid-template-columns: repeat (1, minmax (0, 1fr));

grid-gap: 24px;

`;

export const StyledCardLink = styled.a`

text-decoration: none;

color: #000;

`;

export const StyledCard = styled.div`

display: flex;

gap: 12px;

padding: 12px;

background-color: #f7f7f7;

`;

export const StyledCardColumn = styled.div`

display: flex;

flex-direction: column;

gap: 4px;

justify-content: space-between;

`;

export const StyledCardRow = styled.div`

display: flex;

flex-direction: column;

gap: 4px;

`;

export const StyledCardThumbnailContainer = styled.div`

object-fit: cover;

width: 150px;

height: 150px;

position: relative;

`;

export const StyledCardTitle = styled.div`

font-size: 18px;

font-weight: bold;

`;

export const StyledCardTagline = styled.div`

font-size: 14px;

line-height: 1.5;

`;

Теперь, если мы запустим yarn startкоманду в новом окне терминала, мы увидим следующий экран на http: //localhost:4200/.

Ошибка сервера

Чтобы решить вышеуказанную проблему, нам нужно обновить наш apps/product-hunt/next.config.jsфайл со следующим содержимым:

// apps/product-hunt/next.config.js

// eslint-disable-next-line @typescript-eslint/no-var-requires

const withNx = require („@nrwl/next/plugins/with-nx“) ;

module.exports = withNx ({

nx: {

// Set this to false if you do not want to use SVGR

// See: https://github.com/gregberge/svgr

svgr: true,

},

images: {

domains: [„ph-files.imgix.net“, „ph-avatars.imgix.net“],

},

}) ;

Мы добавили домены, из которых API Product Hunt получает изображения. Это необходимо, потому что мы используем компонент Next Image.

Теперь, если мы перезапустим наш сервер, мы сможем увидеть следующий экран на http: //localhost:4200/.

Демонстрационная страница Product Hunt

Создание повторно используемой библиотеки компонентов

Мы успешно создали первую страницу Product Hunt. Однако мы видим, что все наши стили находятся в одном приложении. Итак, если мы хотим повторно использовать одни и те же стили при создании другого приложения, нам придется скопировать эти стили в новое приложение.

Одним из способов решения этой проблемы является создание отдельной библиотеки компонентов и сохранение в ней этих стилей. Эта библиотека компонентов может быть повторно использована несколькими приложениями.

Чтобы создать новую библиотеку React в Nx, мы можем запустить следующую команду из корня нашего проекта:

nx generate @nrwl/react: library components

Приведенная выше команда даст нам приглашение, изображенное ниже.

Выберите формат таблицы стилей

Поскольку мы используем стилизованные компоненты, мы выберем этот вариант в приглашении выше. Как только мы выберем эту опцию, мы увидим следующие изменения на нашем терминале.

Список сгенерированных файлов

Далее мы скопируем все стили из apps/product-hunt/public/styles.tsв libs/components/src/lib/components.tsxфайл.

Нам также нужно импортировать все стили из этой библиотеки. Для этого нам нужно изменить наш apps/product-hunt/pages/index.tsxфайл:

// apps/product-hunt/pages/index.tsx

import {

StyledCard,

StyledCardColumn,

StyledCardLink,

StyledCardRow,

StyledCardTagline,

StyledCardThumbnailContainer,

StyledCardTitle,

StyledContainer,

StyledGrid,

} from „@nx-nextjs-monorepo/components“;

Если мы посмотрим на наш tsconfig.base.jsonфайл, мы увидим следующую строку:

// tsconfig.base.json

„paths“: {

„@nx-nextjs-monorepo/components“: [»libs/components/src/index.ts"]

}

@nx-nextjs-monorepo/componentsэто имя нашей библиотеки компонентов. Следовательно, мы импортировали все стили из этой библиотеки в apps/product-hunt/pages/index.tsxфайл.

Мы можем удалить apps/product-hunt/public/styles.tsфайл, так как он нам больше не нужен.

Теперь, если мы перезапустим наш сервер Nx, мы увидим следующий экран на http: //localhost:4200/.

Демонстрация Produzct Hunt все еще работает

Заключение

В этой статье мы узнали, как использовать Nx для создания монорепозитория с Next.js и Styled Components. Мы также узнали, как использование монорепозиториев может улучшить процесс разработки и скорость создания приложений. Мы создали приложение Next.js и библиотеку Styled Components, но с помощью Nx можно создавать приложения Angular, Cypress, Nest, Gatsby, Express и Storybook, используя их генераторы.

3D-печать5GABC-анализAndroidAppleAppStoreAsusCall-центрChatGPTCRMDellDNSDrupalExcelFacebookFMCGGoogleHuaweiInstagramiPhoneLinkedInLinuxMagentoMicrosoftNvidiaOpenCartPlayStationPOS материалPPC-специалистRuTubeSamsungSEO-услугиSMMSnapchatSonyStarlinkTikTokTwitterUbuntuUp-saleViasatVPNWhatsAppWindowsWordPressXiaomiYouTubeZoomАвдеевкаАктивные продажиАкцияАлександровск ЛНРАлмазнаяАлчевскАмвросиевкаАнализ конкурентовАнализ продажАнтимерчандайзингАнтрацитАртемовскАртемовск ЛНРАссортиментная политикаБелгородБелицкоеБелозерскоеБердянскБизнес-идеи (стартапы)БрендБрянкаБукингВахрушевоВендорВидеоВикипедияВирусная рекламаВирусный маркетингВладивостокВнутренние продажиВнутренний маркетингВолгоградВолновахаВоронежГорловкаГорнякГорскоеДебальцевоДебиторкаДебиторская задолженностьДезинтермедитацияДзержинскДивизионная система управленияДизайнДимитровДирект-маркетингДисконтДистрибьюторДистрибьюцияДобропольеДокучаевскДоменДружковкаЕкатеринбургЕнакиевоЖдановкаЗапорожьеЗимогорьеЗолотоеЗоринскЗугрэсИжевскИловайскИрминоКазаньКалининградКировскКировскоеКомсомольскоеКонстантиновкаКонтент-маркетингКонтент-планКопирайтингКраматорскКрасноармейскКрасногоровкаКраснодарКраснодонКраснопартизанскКрасный ЛиманКрасный ЛучКременнаяКураховоКурскЛисичанскЛуганскЛутугиноМакеевкаМариупольМаркетингМаркетинговая информацияМаркетинговые исследованияМаркетинговый каналМаркетинг услугМаркетологМарьинкаМедиаМелекиноМелитопольМенеджментМерчандайзерМерчандайзингМиусинскМолодогвардейскМоскваМоспиноНижний НовгородНиколаевНиколаевкаНишевой маркетингНовоазовскНовогродовкаНоводружескНовосибирскНумерическая дистрибьюцияОдессаОмскОтдел маркетингаПартизанский маркетингПервомайскПеревальскПетровскоеПлата за кликПоисковая оптимизацияПопаснаяПравило ПаретоПривольеПрогнозирование продажПродвижение сайтов в ДонецкеПроизводство видеоПромоПромоушнПрямой маркетингРабота для маркетологаРабота для студентаРазработка приложенийРаспродажаРегиональные продажиРекламаРеклама на асфальтеРемаркетингРетро-бонусРибейтРитейлРовенькиРодинскоеРостов-на-ДонуРубежноеСамараСанкт-ПетербургСаратовСватовоСвердловскСветлодарскСвятогорскСевастопольСеверодонецкСеверскСедовоСейлз промоушнСелидовоСимферопольСинергияСколковоСлавянскСнежноеСоздание сайтов в ДонецкеСоледарСоциальные сетиСочиСтаробельскСтаробешевоСтахановСтимулирование сбытаСуходольскСчастьеТелемаркетингТельмановоТираспольТорговый представительТорезТрейд маркетингТрейд промоушнТюменьУглегорскУгледарУкраинскХабаровскХарцызскХерсонХостингЦелевая аудиторияЦифровой маркетингЧасов ЯрЧелябинскШахтерскЮжно-СахалинскЮнокоммунаровскЯндексЯсиноватая