From 0aecf6959986817d9315df90c898da55a8a64290 Mon Sep 17 00:00:00 2001 From: Manuel Correia <20400660+manuelc2209@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:54:24 +0100 Subject: [PATCH] Update nextjs docs (#2080) --- .../tutorials/integrating-with-nextjs.md | 112 ++++++++++++++++-- 1 file changed, 105 insertions(+), 7 deletions(-) diff --git a/docs/pages/tutorials/integrating-with-nextjs.md b/docs/pages/tutorials/integrating-with-nextjs.md index 76348424..38f7e165 100644 --- a/docs/pages/tutorials/integrating-with-nextjs.md +++ b/docs/pages/tutorials/integrating-with-nextjs.md @@ -12,16 +12,12 @@ This page explains how to integrate Shoelace with a NextJS app. This is a community-maintained document. Please [ask the community](/resources/community) if you have questions about this integration. You can also [suggest improvements](https://github.com/shoelace-style/shoelace/blob/next/docs/tutorials/integrating-with-nextjs.md) to make it better. ::: -## Requirements - -This integration has been tested with the following: +## Instructions - Next 12.1.6 - Node: 16.13.1 - NextJS: 12.1.6 - Shoelace: 2.0.0-beta.74 -## Instructions - To get started using Shoelace with NextJS, the following packages must be installed. ```bash @@ -105,7 +101,109 @@ function MyApp({ Component, pageProps, URL }) { } ``` -### Environmental Variable +## Instructions - Next 14.2.4 + +- Node: v20.11.1 +- NextJS: 14.2.4 +- Shoelace: 2.15.1 + +To get started using Shoelace with NextJS, the following packages must be installed. + +```bash +yarn add @shoelace-style/shoelace +``` + +### Importing the Default Theme + +The next step is to import Shoelace's default theme (stylesheet) in your `_app.js` file: + +```css +import '@shoelace-style/shoelace/dist/themes/light.css'; +``` + +### Defining Custom Elements + +After importing the theme, you'll need to import the JavaScript files for Shoelace. However, this is a bit tricky to do in NextJS thanks to the SSR environment not having any of the required browser APIs to define endpoints. + +We'll want to create a component that uses [React's `useLayoutEffect`](https://reactjs.org/docs/hooks-reference.html#uselayouteffect) to add in the custom components before the first render: + +```javascript +function CustomEls({ URL }) { + // useRef to avoid re-renders + const customEls = useRef(false); + + useLayoutEffect(() => { + if (customEls.current) { + return; + } + + import('@shoelace-style/shoelace/dist/utilities/base-path').then(({ setBasePath }) => { + setBasePath(`${URL}/static/static`); + + // This imports all components + import('@shoelace-style/shoelace/dist/react'); + // If you're wanting to selectively import components, replace this line with your own definitions + + // import("@shoelace-style/shoelace/dist/components/button/button"); + customEls.current = true; + }); + }, [URL, customEls]); + + return null; +} +``` + +:::tip +If we use `useEffect` instead of `useLayoutEffect`, the initial render will occur with the expected `sl-` props applied, but the subsequent render (caused by the `useEffect`) will remove those props as the custom components initialize. We _must_ use `useLayoutEffect` to have expected behavior +::: + +:::tip +This will import all Shoelace components for convenience. To selectively import components, refer to the [Using webpack](/getting-started/installation#using-webpack) section of the docs. +::: + +You may be wondering where the `URL` property is coming from. We'll address that in the next few sections. + +### Using Our New Component CustomEls In Code + +While we need to use `useLayoutEffect` for the initial render, NextJS will throw a warning at us for trying to use `useLayoutEffect` in SSR, which is disallowed. To fix this problem, we'll conditionally render the `CustomEls` component to only render in the browser + +```javascript +function MyApp({ Component, pageProps, URL }) { + const isBrowser = typeof window !== 'undefined'; + return ( + <> + {isBrowser && } + + + ); +} +``` + +### Importing Shoelace Components + +After importing the customElement in your `_app.tsx` e.g., you now can import the components. + +We will need to mark the component as 'use client' + +```javascript +'use client'; +import dynamic from 'next/dynamic'; + +const SlButton = dynamic(() => import('@shoelace-style/shoelace/dist/react/button'), { + loading: () =>

Loading...

, + ssr: false +}); + +export default function Sample() { + return Button; +} +``` + +:::warning +Don't forget to mark your component to 'use client'. +::: + +## Environmental Variable However, to make `setBasePath()` work as-expected, we need to know where the file is hosted. To do this, we need to set [environmental variables](https://nextjs.org/docs/basic-features/environment-variables). Create a `.local.env` file and put the following inside: @@ -129,7 +227,7 @@ MyApp.getInitialProps = async context => { You'll need to set this `BASE_URL` variable inside the build process of whatever local build or CI/CD you have. This will need to be an absolute URL, as a relative URL will cause shoelace to throw a warning ::: -### webpack Config +## webpack Config Next we need to add Shoelace's assets to the final build output. To do this, modify `next.config.js` to look like this.