title |
---|
Scaffold |
Scaffold is our boilerplate for Next.js applications, it serves as the starting point for all web projects at Lightbase.
It provides an opinionated set of defaults to assist developers in creating maintainable applications.
:::note
Some of these features are managed by next-preset, which is included in the Scaffold.
:::
You can use create-next-app to quickly scaffold your next project.
create-next-app --example=https://github.com/lightbasenl/scaffold
yarn dev
run the development serveryarn build
build the production appyarn start
run the latest buildyarn storybook
start up storybookyarn test
run unit testsyarn pretty
run prettieryarn lint
run eslint
Base components like <Button>
, <Checkbox>
, <Input>
, etc. that are used throughout the entire app should
live in the src/components
directory. This way they are easily referenced and found. It is recommended that
base components always have a story (see storybook) that shows most intended usages.
Pages live in the src/pages
directory and use the .page.tsx
(for pages) or .api.ts
(for API routes)
extension.
See Next.js routing documentation for more information.
Page components are parts of a page that you don't want to keep in the page's file. Components that are specific to a certain page should be put in the closest directory.
...
├── ...
├── src
│ ├── pages
│ │ ├── about-us
│ │ │ ├── components
│ │ │ │ └── Employee.tsx 👈 The component
│ │ │ └── index.page.tsx 👈 The page component
├── ...
This convention is not optimal, but it is required in order to safely use Next.js' file-based routing and have a clear directory structure.
We use TailwindCSS for styling in all our projects. It allows us to quickly prototype and develop new functionality without having to think about naming classes and managing (S)CSS files.
const Button = () => (
<button className="rounded bg-blue-500 px-6 py-3 text-xl font-medium text-white hover:bg-blue-700">
I'm a button!
</button>
);
:::note
Any unused Tailwind utilities are stripped out in production builds.
:::
Storybook allows us to write documentation as well as quickly prototype and develop base components
(components typically living inside the src/components
directory).
To view storybook run yarn storybook
To add a story to storybook you can create a *.story.tsx
file with the name of your component, this file
should be put in the /stories
directory.
...
├── ...
├── src
│ ├── components
│ │ └── Button.tsx 👈 The component
├── stories
│ └── Button.story.tsx 👈 The story
├── ...
For more documentation see https://storybook.js.org/docs/guides/guide-react/
We're using next-i18next for handling localisation. This allows us to only ship the required translations to pages, reducing bundle size and network load.
Locale files are stored inside the /public
directory and are always publicly available.
...
├── ...
├── public
│ ├── locales
│ │ └── nl
│ │ └── home.json
├── ...
- React Query: Our data-fetching and global cache solution of choice. React Query has proven to completely remove our need for state management solutions like Redux and MobX in our applications.
- Formik: Our form library of choice. It provides all the primitives you generally need to build a form.
- Yup: Validation library mostly used together with Formik.
- Headless UI: Accessible components like: slide-overs, modals and notifications.
- react-focus-on: Primitives for creating accessible components when Headless UI is too opinionated.
- Framer Motion: Framer Motion is our go-to solution for complex animations. E.g. elaborate transitions and animations that can't be easily achieved through CSS.
- date-fns: Our date library of choice.
These headers are configured by default, because they're considered good security practice. You can overwrite
these headers by
setting the header yourself in next.config.js
.
Header | Value |
---|---|
x-frame-options | deny |
content-security-policy. | frame-ancestors 'none' |
x-content-type-options | nosniff |
Referrer-Policy | same-origin |
Strict-Transport-Security | max-age=31536000 |
Permissions-Policy | interest-cohort=() |
When next-preset is used, a check is run on next build
to make sure that the output does not contain any
non-ES5 JavaScript code. This is done so your app does not unexpectedly break in certain browsers.
When offending output is found, the build fails and you're notified.
[PRESET] Checking browser compatibility...
[PRESET]
You might want to add the following entries to `preset.transpileModules` in `next.config.js`:
- yup
For more information, see: https://github.com/martpie/next-transpile-modules
Most modules can be transpiled. Modules that can't be transpiled can be ignored. Be sure to check if the module can be safely ignored or if you need to take additional steps per the modules' instructions.
Modules to be transpiled can be added by setting the preset.transpileModules
option in next.config.js
.
const { withPreset } = require("@lightbase/next-preset");
module.exports = withPreset({
...
preset: {
transpileModules: [
"yup",
"dequal",
],
...
},
...
});
Some modules produce non-ES5 code and cannot be transpiled, e.g. Mapbox-GL. Usually the module does not support older browsers, so it does not make sense for them to transpile to ES5 or support it.
Modules to be ignored can be added by setting the preset.ignoreModules
option in next.config.js
.
const { withPreset } = require("@lightbase/next-preset");
module.exports = withPreset({
...
preset: {
ignoreModules: ["mapbox-gl"],
...
},
...
});
In order for the browser compatibility check to function, source maps are enabled and will be available alongside your app.
If you're using @sentry/nextjs, source maps are already enabled.
Sometimes you'd want to use some logic written for one component for another. These pieces of logic can easily
be extracted into a function in the src/lib
directory. It is recommended that all functions have a unit test
*.test.ts
associated with them.
Scaffold, like this document, is subject to change. With every project there is something new to learn, these learnings can be proposed, discussed and implemented via PR's in the lightbasenl/scaffold repository.
We should always try to backport these changes to our entire portfolio of projects as much as possible. That's why Scaffold is part of the Lightbase Core initiative.