# Integrating with NextJS

This page explains how to integrate Stallion with a NextJS app. This is a community-maintained document. For questions about this integration, please [ask the community](/getting-started/community).

## Requirements

This integration has been tested with the following:

- Node >= 12.10
- NextJS >= 10.0.5

## Instructions

To get started using Stallion with NextJS, the following packages must be installed.

```bash
yarn add @apaq/stallion @apaq/stallion-react copy-webpack-plugin
```

### Importing the Default Theme

The next step is to import Stallion's default theme (stylesheet) in your `_app.js` file:

```css
@import '~@apaq/stallion/dist/stallion/stallion';
```

### Defining Custom Elements

After importing the theme, you'll need to import the JavaScript files for Stallion. 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;
    }
    setAssetPath(`${URL}/static/static`);
    // If you're wanting to selectively import components, replace this line with your own definitions
    defineCustomElements();
    // customElements.define("sl-button", SlButton);
    customEls.current = true;
  }, [URL, customEls]);

  return null;
}
```

?> 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

?> This will import all Stallion components for convenience. To selectively import components, refer to the [Using webpack](/getting-started/installation?id=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 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 }) {
  return (
    <>
      {process.browser && <CustomEls URL={URL} />}
      <Component {...pageProps} />
    </>
  )
}
```

### Environmental Variable

However, to make the `setAssetsPath` 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:

```
BASE_URL="localhost:3000"
```

Then, modify your `MyApp` class in `_app.js` to pass this process environment into your render:

```javascript
MyApp.getInitialProps = async (context) => {
  const URL = process.env.BASE_URL;

  return {
    URL,
  };
};
```

?> 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 stallion to throw a warning

### webpack Config

Next we need to add Stallion's icons to the final build output. To do this, modify `next.config.js` to look like this.

```javascript
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
    webpack: (config) => {
        config.plugins.push(
            new CopyPlugin({
                patterns: [
                    {
                        from: path.resolve(
                            __dirname,
                            "node_modules/@apaq/stallion/dist/stallion/icons"
                        ),
                        to: path.resolve(__dirname, "static/icons"),
                    },
                ],
            })
        );
        return config;
    },
};
```

?> This will copy the files from `node_modules` into your `static` folder on every development serve or build. You may want to avoid commiting these into your repo. To do so, simply add `static/icons` into your `.gitignore` folder

