Building a design system using Solidjs, Typescript, SCSS, CSS Variables and Vite - Setup
Tags: solidjs, typescript, css, vite
Published: 2023-04-15 12:21:48

### Introduction
In this tutorial series we will create a design system using SolidJs and Typescript. In my previous design system [tutorial series](https://dev.to/yaldram/build-a-design-system-with-dark-mode-using-react-typescript-scss-cva-and-vite-setup-5778) we created a design system using React, Typescript and Scss which was an improvement over a [previous design system](https://dev.to/yaldram/working-with-styled-system-using-typescript-4mkj) built using React, Typescript, Styled components and Styled systems. This tutorial series goes a step further here unlike the previous tutorial series where we shipped different classes for light and dark modes - `.badge {} & [data-theme="dark"] .badge {}`, in this series we will use CSS Variables for implementing light and dark modes. For this tutorial series all the theme tokens, components are inspired by [nextui](https://nextui.org/). I would encourage you to play around with the deployed [storybook](http://solid-vite-lib.s3-website.ap-south-1.amazonaws.com/?path=/story/atoms-forms-button--playground). All the code for this series is available on [GitHub](https://github.com/yaldram/solid-vite-lib).

### Step One: Bootstrap the component library
I won't go into the details; I would request you to check my other [tutorial](https://dev.to/yaldram/react-component-library-setup-with-vite-typescript-styled-components-styled-system-and-storybook-55ad) on creating a component library from scratch using Vite. From your terminal - 
```bash
mkdir solid-vite-lib 
cd solid-vite-lib
git init
git remote add origin https://github.com/username/repo.git
```
Now after running npm init here is my package.json - 
```json
{
  "name": "@yaldram/solid-vite-lib",
  "version": "0.0.1",
  "description": "A starter project for developing a UI library using SolidJS & Typescript.",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/yaldram/solid-vite-lib.git"
  },
  "author": "Arsalan Yaldram",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/yaldram/solid-vite-lib/issues"
  },
  "homepage": "https://github.com/yaldram/solid-vite-lib#readme"
}  
```
Now lets install our dev dependencies, for building and bundling our project. We require the following - 
```bash
yarn add -D typescript @types/node sass vite @rollup/plugin-typescript tslib vite-plugin-solid
```
- We are installing `sass` the complier for scss.
- We are installing `vite` which will build and bundle our library.
- We are installing `@rollup/plugin-typescript & tslib` for generating the type definition files.

Now let us install our peer dependencies from your terminal run - 
```bash
yarn add -D solid-js
```
Make sure you add solid-js to `peerDependencies` in your package.json because we don't want to bundle them with our library.
```json
"peerDependencies": {
    "solid-js": "^1.7.3"
 }
```
Finally, we install cva as a dependency - 
```
yarn add class-variance-authority
```

### Step Two: Setup vite
Now from the root of our project create a `tsconfig.json` - 
```json
{
  "compilerOptions": {
    "outDir": "dist",
    "module": "esnext",
    "target": "ESNext",
    "lib": ["dom", "esnext"],
    "moduleResolution": "node",
    "jsx": "preserve",
    "jsxImportSource": "solid-js",
    "sourceMap": true,
    "declaration": true,
    "esModuleInterop": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist", "**/*.stories.tsx", "**/*.test.tsx"]
}
```
Make a note that we have added the `"jsxImportSource": "solid-js"`.

Again from the root of our project create a new file `vite.config.ts` - 
```typescript
import { defineConfig } from "vite";
import typescript from "@rollup/plugin-typescript";
import { resolve } from "path";
import solidPlugin from "vite-plugin-solid";

import { peerDependencies } from "./package.json";

export default defineConfig({
  plugins: [solidPlugin()],
  build: {
    outDir: "dist",
    sourcemap: true,
    lib: {
      entry: resolve(__dirname, "src/index.ts"),
      formats: ["es"],
      fileName: "index",
    },

    rollupOptions: {
      external: [...Object.keys(peerDependencies)],
      plugins: [typescript({ tsconfig: "./tsconfig.json" })],
      output: {
        assetFileNames: ({ name = "" }) => {
          /**
           * Vite gives us a single style.css file
           * in the build we are moving it to the css
           * folder and renaming it to main.css
           */
          if (name === "style.css") {
            return "css/main.css";
          }
          return name;
        },
      },
    },
  },
});
```

Finally, we need to make some changes under the `package.json` file - 
```json
 "main": "./dist/index.js",
 "types": "./dist/index.d.ts",
 "source": "src/index.ts",
 "files": [
    "dist"
 ],
 "exports": {
   ".": {
     "import": "./dist/index.mjs"
   },
   "./main.css": {
     "import": "./dist/css/main.css"
   }
 },
 "scripts": {
    "build": "tsc && vite build"
 },
```
Take a note of the `exports` entry in the package.json file : - 
1. The first `.` entry is for importing our components `import { Box } from "@yaldram/solid-vite-lib"`. 
2. The second entry is for importing the css from our library - 
`import "@yaldram/solid-vite-lib/main.css"`.

### Step Three: Storybook setup
We will use the latest and greatest storybook version 7 -
```bash
npx sb@next init
```

Under `.storybook/preview-head.html` paste the following - 
```html
<link rel="preconnect" href="https://fonts.gstatic.com" />

<style>
  * {
    padding: 0;
    margin: 0;
  }

  body {
    font-family: 'Nunito Sans', -apple-system, '.SFNSText-Regular', 'San Francisco',
      BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  }
</style>

<script>
  window.global = window;
</script>
```

Under `.storybook/main.ts` paste the following - 
```typescript
import type { StorybookConfig } from "storybook-solidjs-vite";

const config: StorybookConfig = {
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  framework: {
    name: "storybook-solidjs-vite",
    options: {},
  },
  docs: {
    autodocs: "tag",
  },
};
export default config;
```

Finally under `.storybook` folder rename the `preview.ts` file to `preview.tsx`.

### Step Five: Folder structure
While building components, I follow the atomic design methodology. Create a `src` folder, inside it create a new file `index.ts`. Now create a `components` folder, create 2 folders inside it `atoms` & `molecules`. 

Now inside the atoms folder create a `index.ts` file, and create a new folder `layouts`. Finally, inside `layouts` create an `index.ts` file and create 2 folders `box` & `flex`. Your directory structure should look like

![directory-structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y92sks4zqfwocfyaiclx.png)


Now inside the `box` folder create a new file `index.tsx` - 
```tsx
import { Component, ComponentProps } from "solid-js";

export type BoxProps = ComponentProps<"div">;

export const Box: Component<BoxProps> = (props) => {
  return <div {...props} />;
};
```
Create a new file for the story `box.stories.tsx` - 
```tsx
/** @jsxImportSource solid-js */

import { Box } from ".";

export default {
  title: "Atoms/Layout/Box",
};

export const Default = () => (
  <Box style="padding: 1rem; background: green; color: white; width: 100%">
    Box Component
  </Box>
);
```
Now from your terminal run `yarn storybook` and check the output.

Let's export our Box component under `components/atoms/layouts/index.ts` -
```ts
export * from "./box";
```

Under `/components/atoms/index.ts` - 
```ts
export * from "./layouts";
```

Finally under `src/index.ts` paste the following - 
```ts
export * from "./components/atoms";
```
From the terminal, build the project by running - 
```bash
yarn build
```
It should output a `dist` folder with an `index.mjs` file along with our typescript definition files. You can also test our library by publishing it and importing the `Box` component in a new Solid project. Read more on publishing [here](https://dev.to/yaldram/react-component-library-setup-with-vite-typescript-styled-components-styled-system-and-storybook-55ad).

### Step Six: Setup Eslint and Prettier
From the terminal install the following packages - 
```bash
 yarn add --dev eslint eslint-plugin-solid
```
Now from the terminal run - `npm init @eslint/config`, select none for the framework and yes for Typescript. Now lets add prettier - 
```bash
 yarn add -D prettier eslint-config-prettier eslint-plugin-prettier
```
In the `.eslintrc.json` file - 
```json
{
  "env": {
    "browser": true,
    "es2021": true
  },
  "extends": ["eslint:recommended", "plugin:solid/typescript"],
  "overrides": [],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": ["solid", "prettier"],
  "rules": {
    "solid/reactivity": "error",
    "solid/no-destructure": "error",
    "solid/jsx-no-undef": "error"
  }
}
```
In the `.eslintignore` file - 
```
build/
dist/
node_modules/
storybook-static
.snapshots/
yarn.lock
*.min.js
*.css
*.svg
```
In the .prettierrc file paste - 
```json
{
  "singleQuote": true,
  "jsxSingleQuote": true,
  "semi": false,
  "tabWidth": 2,
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "arrowParens": "always",
  "trailingComma": "none"
}
```
In the .prettierignore file paste - 
```
build/
dist/
node_modules/
storybook-static
.snapshots/
yarn.lock
*.min.js
*.css
*.svg
```
Finally, under the `package.json` add the following scripts - 
```json
"lint": "eslint \"./**/*\"",
"lint:fix": "eslint \"src/**/*\" --fix",
"pretty": "prettier . --write",
```

### Step Seven - Setup Husky hooks
From your terminal run the following -
```bash
yarn add -D husky nano-staged
npx husky install
```
`nano-staged` is lighter and more performant than `lint-staged`. Now from the terminal add a husky `pre-commit` hook
```bash
npx husky add .husky/pre-commit "npx nano-staged"
```
Finally add the following under package.json - 
```bash
 "nano-staged": {
    "*.{js,jsx,ts,tsx}": "prettier --write"
  }
```

### Conclusion 
In this tutorial we added the base setup for our design system library. All the code for this tutorial can be found [here](https://github.com/yaldram/solid-vite-lib/tree/feat/vite-setup). In the next tutorial we will work with scss adding our design tokens (colors, spacing, line-height values). Until next time PEACE.