Skip to content

Instantly share code, notes, and snippets.

@pixelmattersdev
Last active August 22, 2023 10:02
Show Gist options
  • Save pixelmattersdev/ea00073e72c7576b62f98ee7b7c9165d to your computer and use it in GitHub Desktop.
Save pixelmattersdev/ea00073e72c7576b62f98ee7b7c9165d to your computer and use it in GitHub Desktop.
Manage multiple front-end projects with a monorepo
mkdir demo-monorepo
cd demo-monorepo
npm init -y
git init
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"workspaces": [
"apps/*",
"packages/*"
],
"devDependencies": {},
"keywords": [],
"author": "",
"license": "ISC"
}
npx degit pixelmatters/setup-project-demo#v2.0.1 apps/project-one
mv apps/project-one/.github .github
mv apps/project-one/.husky .husky
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": { // This object was updated
"prepare": "husky install"
},
"devDependencies": { // This object was added
"husky": "^8.0.3"
},
"keywords": [],
"author": "",
"license": "ISC"
}
mv apps/project-one/.vscode .vscode
mv apps/project-one/.commitlintrc.json .commitlintrc.json
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"prepare": "husky install"
},
"devDependencies": {
"@commitlint/cli": "^17.6.7", // This line was added
"@commitlint/config-conventional": "^17.6.7", // This line was added
"husky": "^8.0.3"
},
"keywords": [],
"author": "",
"license": "ISC"
}
mv apps/project-one/.nvmrc .nvmrc
rm apps/project-one/package-lock.json
{
"name": "project-one", // This line was updated
"version": "0.0.0",
// ...
}
npm run dev --workspace project-one
// or
npm run dev -w project-one
cp -r apps/project-one apps/project-two
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Project One</title> <!-- This line was updated -->
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
import { useState } from 'react'
import logo from './logo.svg'
import './App.css'
export const App: React.FC = () => {
const [count, setCount] = useState(0)
return (
<div className="app">
<header className="app-header">
<img src={logo} className="app-logo" alt="logo" />
<p>Hello Project One!</p>{/* This line was updated */}
<p>
<button type="button" onClick={() => setCount((count) => count + 1)}>
count is: {count}
</button>
</p>
<p>
Edit <code>App.tsx</code> and save to test HMR updates.
</p>
<p>
<a
className="app-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
{' | '}
<a
className="app-link"
href="https://vitejs.dev/guide/features.html"
target="_blank"
rel="noopener noreferrer"
>
Vite Docs
</a>
</p>
</header>
</div>
)
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Project Two</title> <!-- This line was updated -->
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
import { useState } from 'react'
import logo from './logo.svg'
import './App.css'
export const App: React.FC = () => {
const [count, setCount] = useState(0)
return (
<div className="app">
<header className="app-header">
<img src={logo} className="app-logo" alt="logo" />
<p>Hello Project Two!</p>{/* This line was updated */}
<p>
<button type="button" onClick={() => setCount((count) => count + 1)}>
count is: {count}
</button>
</p>
<p>
Edit <code>App.tsx</code> and save to test HMR updates.
</p>
<p>
<a
className="app-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
{' | '}
<a
className="app-link"
href="https://vitejs.dev/guide/features.html"
target="_blank"
rel="noopener noreferrer"
>
Vite Docs
</a>
</p>
</header>
</div>
)
}
❯ npm run test --workspaces
npm ERR! code EDUPLICATEWORKSPACE
npm ERR! must not have multiple workspaces with the same name
npm ERR! package 'project-one' has conflicts in the following paths:
npm ERR! /Users/ruisaraiva/dev/pixelmatters/demo-monorepo/apps/project-one
npm ERR! /Users/ruisaraiva/dev/pixelmatters/demo-monorepo/apps/project-two
{
"name": "project-two", // This line was updated
"version": "0.0.0",
"engines": {
"node": ">=18.17.0",
"npm": ">=9.0.0"
},
// ...
}
❯ npm run test --workspaces
> project-one@0.0.0 test
> jest
PASS src/demo.test.ts
FAIL src/App.test.tsx
● renders hello message
Test Suites: 1 failed, 1 passed, 2 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 1.932 s, estimated 3 s
Ran all test suites.
> project-two@0.0.0 test
> jest
PASS src/demo.test.ts
FAIL src/App.test.tsx
● renders hello message
Test Suites: 1 failed, 1 passed, 2 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 1.637 s, estimated 2 s
Ran all test suites.
import '@testing-library/jest-dom'
import { render, screen } from '@testing-library/react'
import { App } from './App'
it('renders hello message', () => {
render(<App />)
expect(screen.getByText('Hello Project One!')).toBeInTheDocument() // This line was updated
})
import '@testing-library/jest-dom'
import { render, screen } from '@testing-library/react'
import { App } from './App'
it('renders hello message', () => {
render(<App />)
expect(screen.getByText('Hello Project Two!')).toBeInTheDocument() // This line was updated
})
❯ npm run test --workspaces
> project-one@0.0.0 test
> jest
PASS src/demo.test.ts
PASS src/App.test.tsx
Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.037 s
Ran all test suites.
> project-two@0.0.0 test
> jest
PASS src/demo.test.ts
PASS src/App.test.tsx
Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 1.608 s, estimated 2 s
Ran all test suites.
.
├── .github
│   └── workflows
│   ├── chromatic.yml
│   ├── main.yml
│   └── release.yml
├── .husky
│   └── commit-msg
├── .vscode
│   └── settings.json
├── apps
│   ├── project-one
│   │   ├── .storybook
│   │   ├── __mocks__
│   │   ├── cypress
│   │   ├── src
│   │   ├── .eslintignore
│   │   ├── .eslintrc.json
│   │   ├── .gitignore
│   │   ├── .prettierrc
│   │   ├── .releaserc.json
│   │   ├── .stylelintignore
│   │   ├── .stylelintrc.json
│   │   ├── README.md
│   │   ├── cypress.config.ts
│   │   ├── index.html
│   │   ├── jest.config.ts
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   └── project-two
│   ├── .storybook
│   ├── __mocks__
│   ├── cypress
│   ├── src
│   ├── .eslintignore
│   ├── .eslintrc.json
│   ├── .gitignore
│   ├── .prettierrc
│   ├── .releaserc.json
│   ├── .stylelintignore
│   ├── .stylelintrc.json
│   ├── README.md
│   ├── cypress.config.ts
│   ├── index.html
│   ├── jest.config.ts
│   ├── package.json
│   ├── tsconfig.json
│   ├── tsconfig.node.json
│   └── vite.config.ts
├── .commitlintrc.json
├── .gitignore
├── .nvmrc
├── package-lock.json
└── package.json
npm init -w ./packages/eslint-config -y
mv apps/project-one/.eslintrc.json packages/eslint-config
rm apps/project-two/.eslintrc.json
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:react/jsx-runtime',
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:storybook/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2021,
sourceType: 'module',
tsconfigRootDir: __dirname,
project: ['./apps/**/tsconfig.json', './packages/**/tsconfig.json'],
},
plugins: ['react', '@typescript-eslint'],
rules: {
'prettier/prettier': 'error',
},
settings: {
react: {
version: 'detect',
},
},
};
module.exports = {
env: {
node: true,
},
overrides: [
{
files: ['src/**/*.test.ts', 'src/**/*.test.tsx'],
extends: ['plugin:jest/recommended'],
plugins: ['jest'],
env: {
'jest/globals': true,
},
},
],
};
{
"name": "eslint-config",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"@babel/core": "^7.22.9",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"eslint": "^8.46.0",
"eslint-config-prettier": "^8.9.0",
"eslint-plugin-cypress": "^2.13.3",
"eslint-plugin-jest": "^27.2.3",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react": "^7.33.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"eslint-plugin-storybook": "^0.6.13"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
echo "module.exports = { extends: ['./index'].map(require.resolve) }" > packages/eslint-config/.eslintrc.js
{
"name": "eslint-config",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"@babel/core": "^7.22.9",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"eslint": "^8.46.0",
"eslint-config-prettier": "^8.9.0",
"eslint-plugin-cypress": "^2.13.3",
"eslint-plugin-jest": "^27.2.3",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react": "^7.33.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"eslint-plugin-storybook": "^0.6.13"
},
"devDependencies": {},
"scripts": {
"lint:scripts": "eslint ." // This line was updated
},
"keywords": [],
"author": "",
"license": "ISC"
}
module.exports = {
extends: ['eslint-config', 'eslint-config/jest'].map(require.resolve),
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json',
},
ignorePatterns: ['cypress/**/*', 'dist', '.eslintrc.js'],
}
npm install -D eslint-config -w project-one
npm install -D eslint-config -w project-two
cp apps/project-one/.eslintrc.js apps/project-two
rm apps/project-one/.eslintignore
rm apps/project-two/.eslintignore
npm init -w ./packages/prettier-config -y
mv apps/project-one/.prettierrc packages/prettier-config
rm apps/project-two/.prettierrc
module.exports = {
semi: false,
singleQuote: true,
}
{
"name": "prettier-config",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": { // This object was added
"prettier": "^3.0.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
npm install -D prettier-config -w project-one
npm install -D prettier-config -w project-two
npm install -D prettier-config -w eslint-config
echo "\"prettier-config\"" > apps/project-one/.prettierrc
echo "\"prettier-config\"" > apps/project-two/.prettierrc
echo "\"prettier-config\"" > packages/eslint-config/.prettierrc
echo "\"./index.js\"" > packages/prettier-config/.prettierrc
npm init -w ./packages/stylelint-config -y
mv apps/project-one/.stylelintrc.json packages/stylelint-config
rm apps/project-two/.stylelintrc.json
{
"name": "stylelint-config",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"stylelint": "^15.10.2", // This line was added
"stylelint-config-recess-order": "^4.3.0", // This line was added
"stylelint-config-standard": "^34.0.0" // This line was added
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-config-recess-order'],
}
npm install -D eslint-config prettier-config -w stylelint-config
echo "\"prettier-config\"" > packages/stylelint-config/.prettierrc
echo "module.exports = { extends: ['eslint-config'].map(require.resolve) }" > packages/stylelint-config/.eslintrc.js
npm install -D stylelint-config -w project-one
npm install -D stylelint-config -w project-two
echo "{ \"extends\": \"stylelint-config\" }" > apps/project-one/.stylelintrc.json
echo "{ \"extends\": \"stylelint-config\" }" > apps/project-two/.stylelintrc.json
npm init -w ./packages/release-config -y
mv apps/project-one/.releaserc.json packages/release-config
rm apps/project-two/.releaserc.json
{
"name": "release-config",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": { // This object was added
"semantic-release": "^21.0.7"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
module.exports = {
branches: ['main'],
plugins: [
'@semantic-release/commit-analyzer',
'@semantic-release/release-notes-generator',
'@semantic-release/github',
],
}
npm install -D eslint-config prettier-config -w release-config
echo "\"prettier-config\"" > packages/release-config/.prettierrc
echo "module.exports = { extends: ['eslint-config'].map(require.resolve) }" > packages/release-config/.eslintrc.js
npm install -D release-config -w project-one
npm install -D release-config -w project-two
echo "module.exports = require('release-config')" > apps/project-one/release.config.js
echo "module.exports = require('release-config')" > apps/project-two/release.config.js
.
├── .github
│   └── workflows
│   ├── chromatic.yml
│   ├── main.yml
│   └── release.yml
├── .husky
│   └── commit-msg
├── .vscode
│   └── settings.json
├── apps
│   ├── project-one
│   │   ├── .storybook
│   │   ├── __mocks__
│   │   ├── cypress
│   │   ├── src
│   │   ├── .eslintrc.js
│   │   ├── .gitignore
│   │   ├── .prettierrc
│   │   ├── .stylelintignore
│   │   ├── .stylelintrc.json
│   │   ├── README.md
│   │   ├── cypress.config.ts
│   │   ├── index.html
│   │   ├── jest.config.ts
│   │   ├── package.json
│   │   ├── release.config.js
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   └── project-two
│   ├── .storybook
│   ├── __mocks__
│   ├── cypress
│   ├── src
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── .prettierrc
│   ├── .stylelintignore
│   ├── .stylelintrc.json
│   ├── README.md
│   ├── cypress.config.ts
│   ├── index.html
│   ├── jest.config.ts
│   ├── package.json
│   ├── release.config.js
│   ├── tsconfig.json
│   ├── tsconfig.node.json
│   └── vite.config.ts
├── packages
│   ├── eslint-config
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   ├── jest.js
│   │   └── package.json
│   ├── prettier-config
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   └── package.json
│   ├── release-config
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   └── package.json
│   └── stylelint-config
│   ├── .eslintrc.js
│   ├── .prettierrc
│   ├── index.js
│   └── package.json
├── .commitlintrc.json
├── .gitignore
├── .nvmrc
├── package-lock.json
└── package.json
npm init -w ./apps/design-system -y
mv apps/project-one/.storybook apps/design-system
rm -rf apps/project-two/.storybook
{
"name": "design-system",
"version": "1.0.0",
"description": "",
"main": "index.js",
"devDependencies": {
"@storybook/addon-essentials": "^7.2.0", // This line was added
"@storybook/addon-interactions": "^7.2.0", // This line was added
"@storybook/addon-links": "^7.2.0", // This line was added
"@storybook/addon-onboarding": "^1.0.8", // This line was added
"@storybook/blocks": "^7.2.0", // This line was added
"@storybook/react": "^7.2.0", // This line was added
"@storybook/react-vite": "^7.2.0", // This line was added
"@storybook/testing-library": "^0.2.0", // This line was added
"storybook": "^7.2.0" // This line was added
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
npm install -D eslint-config -w design-system
npm install -D prettier-config -w design-system
echo "\"prettier-config\"" > apps/design-system/.prettierrc
module.exports = {
extends: ['eslint-config'].map(require.resolve),
ignorePatterns: ['!.storybook'],
}
{
"name": "design-system",
"version": "1.0.0",
"description": "",
"main": "index.js",
"devDependencies": {
"@storybook/addon-essentials": "^7.2.0",
"@storybook/addon-interactions": "^7.2.0",
"@storybook/addon-links": "^7.2.0",
"@storybook/addon-onboarding": "^1.0.8",
"@storybook/blocks": "^7.2.0",
"@storybook/react": "^7.2.0",
"@storybook/react-vite": "^7.2.0",
"@storybook/testing-library": "^0.2.0",
"eslint-config": "^1.0.0",
"prettier-config": "^1.0.0",
"storybook": "^7.2.0"
},
"scripts": {
"dev": "storybook dev -p 6006", // This line was added
"build": "storybook build" // This line was added
},
"keywords": [],
"author": "",
"license": "ISC"
}
npm run dev -w apps/design-system
[vite] Internal server error: Failed to resolve import "../src/index.css" from ".storybook/preview.js". Does the file exist?
import type { StorybookConfig } from '@storybook/react-vite'
const config: StorybookConfig = {
stories: ['../../*/src/**/*.stories.@(js|jsx|ts|tsx)'], // This line was updated
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-onboarding',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
}
export default config
🚨 Unable to index ../project-one/src/App.stories.tsx,../project-two/src/App.stories.tsx:
Error: Duplicate stories with id: components-app--default
import { Meta, StoryObj } from '@storybook/react'
import { App } from './App'
const meta = {
title: 'Project One/Components/App', // This line was updated
component: App,
} satisfies Meta<typeof App>
export default meta
type Story = StoryObj<typeof meta>
export const Default = {} satisfies Story
import { Meta, StoryObj } from '@storybook/react'
import { App } from './App'
const meta = {
title: 'Project Two/Components/App', // This line was updated
component: App,
} satisfies Meta<typeof App>
export default meta
type Story = StoryObj<typeof meta>
export const Default = {} satisfies Story
npm init -w ./packages/shared -y
mv apps/project-one/src/index.css packages/shared/src/
rm apps/project-two/src/index.css
npm install shared -w apps/project-one
npm install shared -w apps/project-two
npm install shared -w apps/design-system
import type { Preview } from '@storybook/react'
import 'shared/src/index.css' // This line was added
const preview: Preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
layout: 'fullscreen',
},
}
export default preview
import React from 'react'
import ReactDOM from 'react-dom/client'
import 'shared/src/index.css' // This line was updated
import { App } from './App'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
.
├── .github
│   └── workflows
│   ├── chromatic.yml
│   ├── main.yml
│   └── release.yml
├── .husky
│   └── commit-msg
├── .vscode
│   └── settings.json
├── apps
│   ├── design-system
│   │   ├── .storybook
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   └── package.json
│   ├── project-one
│   │   ├── __mocks__
│   │   ├── cypress
│   │   ├── src
│   │   ├── .eslintrc.js
│   │   ├── .gitignore
│   │   ├── .prettierrc
│   │   ├── .stylelintignore
│   │   ├── .stylelintrc.json
│   │   ├── README.md
│   │   ├── cypress.config.ts
│   │   ├── index.html
│   │   ├── jest.config.ts
│   │   ├── package.json
│   │   ├── release.config.js
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   └── project-two
│   ├── .storybook
│   ├── __mocks__
│   ├── cypress
│   ├── src
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── .prettierrc
│   ├── .stylelintignore
│   ├── .stylelintrc.json
│   ├── README.md
│   ├── cypress.config.ts
│   ├── index.html
│   ├── jest.config.ts
│   ├── package.json
│   ├── release.config.js
│   ├── tsconfig.json
│   ├── tsconfig.node.json
│   └── vite.config.ts
├── packages
│   ├── eslint-config
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   ├── jest.js
│   │   └── package.json
│   ├── prettier-config
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   └── package.json
│   ├── release-config
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   └── package.json
│   ├── shared
│   │   ├── src
│   │   └── package.json
│   └── stylelint-config
│   ├── .eslintrc.js
│   ├── .prettierrc
│   ├── index.js
│   └── package.json
├── .commitlintrc.json
├── .gitignore
├── .nvmrc
├── package-lock.json
└── package.json
npm install turbo -D
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"dev": {
"cache": false
},
}
}
node_modules
.DS_Store
dist
dist-ssr
*.local
storybook-static
# The next line was added
.turbo
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"prepare": "husky install",
"dev": "turbo dev --parallel --continue" // This line was added
},
"devDependencies": {
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"husky": "^8.0.3",
"turbo": "^1.10.12"
},
"keywords": [],
"author": "",
"license": "ISC"
}
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"dev": {
"cache": false
},
"build": { // This object was added
"dependsOn": ["^build"],
"outputs": ["dist/**", "storybook-static/**"]
}
}
}
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"prepare": "husky install",
"dev": "turbo dev --parallel --continue",
"build": "turbo build" // This line was added
},
"devDependencies": {
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"husky": "^8.0.3",
"turbo": "^1.10.12"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Tasks: 3 successful, 3 total
Cached: 0 cached, 3 total
Time: 8.067s
Tasks: 3 successful, 3 total
Cached: 3 cached, 3 total
Time: 128ms >>> FULL TURBO
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"dev": {
"cache": false
},
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "storybook-static/**"]
},
"test": { // This object was added
"dependsOn": ["^build"],
"outputs": [],
"inputs": ["src/**/*.tsx", "src/**/*.ts"]
}
}
}
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"prepare": "husky install",
"dev": "turbo dev --parallel --continue",
"build": "turbo build",
"test": "turbo test" // This line was added
},
"devDependencies": {
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"husky": "^8.0.3",
"turbo": "^1.10.12"
},
"keywords": [],
"author": "",
"license": "ISC"
}
command (/Users/ruisaraiva/.../demo-monorepo/packages/shared) npm run test exited (1)
command (/Users/ruisaraiva/.../demo-monorepo/packages/stylelint-config) npm run test exited (1)
Tasks: 0 successful, 2 total
Cached: 0 cached, 2 total
Time: 794ms
ERROR run failed: command exited (1)
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1" // Remove this line
},
❯ npm run test
> demo-monorepo@1.0.0 test
> turbo test
• Packages in scope: design-system, eslint-config, prettier-config, project-one, project-two, release-config, shared, stylelint-config
• Running test in 8 packages
• Remote caching disabled
project-two:test: cache miss, executing 6f5ffb2848ba9d11
project-one:test: cache miss, executing 44571033308de93b
project-one:test:
project-one:test: > project-one@0.0.0 test
project-one:test: > jest
project-one:test:
project-two:test:
project-two:test: > project-two@0.0.0 test
project-two:test: > jest
project-two:test:
project-one:test: PASS src/App.test.tsx
project-two:test: PASS src/App.test.tsx
project-two:test: PASS src/demo.test.ts
project-one:test: PASS src/demo.test.ts
project-two:test:
project-two:test: Test Suites: 2 passed, 2 total
project-two:test: Tests: 2 passed, 2 total
project-two:test: Snapshots: 0 total
project-two:test: Time: 0.787 s, estimated 1 s
project-two:test: Ran all test suites.
project-one:test:
project-one:test: Test Suites: 2 passed, 2 total
project-one:test: Tests: 2 passed, 2 total
project-one:test: Snapshots: 0 total
project-one:test: Time: 0.787 s, estimated 1 s
project-one:test: Ran all test suites.
Tasks: 2 successful, 2 total
Cached: 0 cached, 2 total
Time: 2.946s
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"dev": {
"cache": false
},
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "storybook-static/**"]
},
"test": {
"dependsOn": ["^build"],
"outputs": [],
"inputs": ["src/**/*.tsx", "src/**/*.ts"]
},
"lint": { // This object was added
"dependsOn": ["^build"],
"outputs": []
}
}
}
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"prepare": "husky install",
"dev": "turbo dev --parallel --continue",
"build": "turbo build",
"test": "turbo test",
"lint": "turbo lint" // This line was added
},
"devDependencies": {
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"husky": "^8.0.3",
"turbo": "^1.10.12"
},
"keywords": [],
"author": "",
"license": "ISC"
}
❯ npm run lint
> demo-monorepo@1.0.0 lint
> turbo lint
• Packages in scope: design-system, eslint-config, prettier-config, project-one, project-two, release-config, shared, stylelint-config
• Running lint in 8 packages
• Remote caching disabled
No tasks were executed as part of this run.
Tasks: 0 successful, 0 total
Cached: 0 cached, 0 total
Time: 146ms
{
"name": "project-one",
"version": "0.0.0",
"engines": {
"node": ">=18.17.0",
"npm": ">=9.0.0"
},
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"lint": "npm run lint:scripts && npm run lint:styles", // This line was added
"lint:scripts": "TIMING=1 eslint --ext .ts,.tsx .", // This line was updated
"lint:styles": "stylelint \"src/**/*.css\"",
"test": "jest",
"cypress:open": "cypress open"
},
// ...
}
❯ npm run lint
> demo-monorepo@1.0.0 lint
> turbo lint
• Packages in scope: design-system, eslint-config, prettier-config, project-one, project-two, release-config, shared, stylelint-config
• Running lint in 8 packages
• Remote caching disabled
project-two:lint: cache miss, executing c1987b986258151d
project-one:lint: cache miss, executing 31c5a2d919a903ba
project-one:lint:
project-one:lint: > project-one@0.0.0 lint
project-one:lint: > npm run lint:scripts && npm run lint:styles
project-one:lint:
project-two:lint:
project-two:lint: > project-two@0.0.0 lint
project-two:lint: > npm run lint:scripts && npm run lint:styles
project-two:lint:
project-one:lint:
project-one:lint: > project-one@0.0.0 lint:scripts
project-one:lint: > TIMING=1 eslint --ext .ts,.tsx .
project-one:lint:
project-two:lint:
project-two:lint: > project-two@0.0.0 lint:scripts
project-two:lint: > TIMING=1 eslint --ext .ts,.tsx .
project-two:lint:
project-one:lint: Rule | Time (ms) | Relative
project-one:lint: :---------------------------------------|----------:|--------:
project-one:lint: prettier/prettier | 205.426 | 52.1%
project-one:lint: @typescript-eslint/no-misused-promises | 85.829 | 21.8%
project-one:lint: @typescript-eslint/no-floating-promises | 39.324 | 10.0%
project-one:lint: @typescript-eslint/no-unsafe-assignment | 14.449 | 3.7%
project-one:lint: @typescript-eslint/no-unsafe-argument | 14.211 | 3.6%
project-one:lint: react/display-name | 7.677 | 1.9%
project-one:lint: @typescript-eslint/no-unused-vars | 4.060 | 1.0%
project-one:lint: react/no-direct-mutation-state | 1.607 | 0.4%
project-one:lint: @typescript-eslint/no-unsafe-return | 1.424 | 0.4%
project-one:lint: react/no-unknown-property | 1.221 | 0.3%
project-two:lint: Rule | Time (ms) | Relative
project-two:lint: :---------------------------------------|----------:|--------:
project-two:lint: prettier/prettier | 216.367 | 53.2%
project-two:lint: @typescript-eslint/no-misused-promises | 85.785 | 21.1%
project-two:lint: @typescript-eslint/no-floating-promises | 38.538 | 9.5%
project-two:lint: @typescript-eslint/no-unsafe-argument | 14.407 | 3.5%
project-two:lint: @typescript-eslint/no-unsafe-assignment | 14.117 | 3.5%
project-two:lint: react/display-name | 7.757 | 1.9%
project-two:lint: @typescript-eslint/no-unused-vars | 5.955 | 1.5%
project-two:lint: @typescript-eslint/no-unsafe-return | 1.787 | 0.4%
project-two:lint: react/no-direct-mutation-state | 1.694 | 0.4%
project-two:lint: react/no-unknown-property | 1.288 | 0.3%
project-one:lint:
project-one:lint: > project-one@0.0.0 lint:styles
project-one:lint: > stylelint "src/**/*.css"
project-one:lint:
project-two:lint:
project-two:lint: > project-two@0.0.0 lint:styles
project-two:lint: > stylelint "src/**/*.css"
project-two:lint:
Tasks: 2 successful, 2 total
Cached: 0 cached, 2 total
Time: 4.902s
.
├── .github
│   └── workflows
│   ├── chromatic.yml
│   ├── main.yml
│   └── release.yml
├── .husky
│   └── commit-msg
├── .vscode
│   └── settings.json
├── apps
│   ├── design-system
│   │   ├── .storybook
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   └── package.json
│   ├── project-one
│   │   ├── __mocks__
│   │   ├── cypress
│   │   ├── src
│   │   ├── .eslintrc.js
│   │   ├── .gitignore
│   │   ├── .prettierrc
│   │   ├── .stylelintignore
│   │   ├── .stylelintrc.json
│   │   ├── README.md
│   │   ├── cypress.config.ts
│   │   ├── index.html
│   │   ├── jest.config.ts
│   │   ├── package.json
│   │   ├── release.config.js
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   └── project-two
│   ├── .storybook
│   ├── __mocks__
│   ├── cypress
│   ├── src
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── .prettierrc
│   ├── .stylelintignore
│   ├── .stylelintrc.json
│   ├── README.md
│   ├── cypress.config.ts
│   ├── index.html
│   ├── jest.config.ts
│   ├── package.json
│   ├── release.config.js
│   ├── tsconfig.json
│   ├── tsconfig.node.json
│   └── vite.config.ts
├── packages
│   ├── eslint-config
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   ├── jest.js
│   │   └── package.json
│   ├── prettier-config
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   └── package.json
│   ├── release-config
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   └── package.json
│   ├── shared
│   │   ├── src
│   │   └── package.json
│   └── stylelint-config
│   ├── .eslintrc.js
│   ├── .prettierrc
│   ├── index.js
│   └── package.json
├── .commitlintrc.json
├── .gitignore
├── .nvmrc
├── package-lock.json
├── package.json
└── turbo.json
name: "Main"
on: pull_request
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run Linters
run: npm run lint
test:
runs-on: ubuntu-latest
strategy:
matrix:
project: [project-one, project-two]
fail-fast: false
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run Tests
run: npm test -- --filter="{${{ matrix.project }}}..."
env:
CI: true
- name: Install Cypress dependencies
uses: cypress-io/github-action@v5
with:
# just perform install
runTests: false
- name: Run Cypress
uses: cypress-io/github-action@v5
with:
build: npm run build
start: npm run serve -- --port=5173
wait-on: "http://127.0.0.1:5173"
browser: chrome
# we have already installed all dependencies above
install: false
working-directory: apps/${{ matrix.project }}
npm install -D semantic-release-monorepo -w project-one
npm install -D semantic-release-monorepo -w project-two
{
"name": "project-one",
"version": "0.0.0",
"engines": {
"node": ">=18.17.0",
"npm": ">=9.0.0"
},
"scripts": {
"dev": "vite --host",
"build": "vite build",
"serve": "vite preview --host",
"lint": "npm run lint:scripts && npm run lint:styles",
"lint:scripts": "TIMING=1 eslint --ext .ts,.tsx .",
"lint:styles": "stylelint \"src/**/*.css\"",
"test": "jest",
"cypress:open": "cypress open",
"release": "semantic-release -e semantic-release-monorepo" // This line was added
},
// ...
}
const sharedConfig = require('release-config')
const { name } = require('./package.json')
module.exports = {
...sharedConfig,
tagFormat: `${name}@\${version}`,
}
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"dev": {
"cache": false
},
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "storybook-static/**"]
},
"test": {
"dependsOn": ["^build"],
"outputs": [],
"inputs": ["src/**/*.tsx", "src/**/*.ts"]
},
"lint": {
"dependsOn": ["^build"],
"outputs": []
},
"release": { // This object was added
"cache": false
}
}
}
{
"name": "demo-monorepo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"prepare": "husky install",
"dev": "turbo dev --parallel --continue",
"build": "turbo build",
"test": "turbo test",
"lint": "turbo lint",
"release": "turbo release --concurrency=1" // This line was added
},
"devDependencies": {
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"husky": "^8.0.3",
"turbo": "^1.10.12"
},
"keywords": [],
"author": "",
"license": "ISC"
}
name: "Release"
on:
push:
branches:
- main
jobs:
semantic-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Release a new version
# 👇 This line was updated
run: npm run release
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
name: "Chromatic"
on: push
jobs:
chromatic-deployment:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 50
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
cache: "npm"
- name: Install dependencies
run: npm ci
# 👇 This step was added
- name: Build Storybook dependencies
run: npm run build -- --filter="design-system^..."
- name: Publish to Chromatic
uses: chromaui/action@v1
with:
# 👇 This line was added
workingDir: apps/design-system
# 👇 This line was added
buildScriptName: build
token: ${{ secrets.GITHUB_TOKEN }}
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
autoAcceptChanges: ${{ github.ref == 'refs/heads/main' }}
exitOnceUploaded: true
skip: "dependabot/**"
.
├── .github
│   └── workflows
│   ├── chromatic.yml
│   ├── main.yml
│   └── release.yml
├── .husky
│   └── commit-msg
├── .vscode
│   └── settings.json
├── apps
│   ├── design-system
│   │   ├── .storybook
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   └── package.json
│   ├── project-one
│   │   ├── __mocks__
│   │   ├── cypress
│   │   ├── src
│   │   ├── .eslintrc.js
│   │   ├── .gitignore
│   │   ├── .prettierrc
│   │   ├── .stylelintignore
│   │   ├── .stylelintrc.json
│   │   ├── README.md
│   │   ├── cypress.config.ts
│   │   ├── index.html
│   │   ├── jest.config.ts
│   │   ├── package.json
│   │   ├── release.config.js
│   │   ├── tsconfig.json
│   │   ├── tsconfig.node.json
│   │   └── vite.config.ts
│   └── project-two
│   ├── .storybook
│   ├── __mocks__
│   ├── cypress
│   ├── src
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── .prettierrc
│   ├── .stylelintignore
│   ├── .stylelintrc.json
│   ├── README.md
│   ├── cypress.config.ts
│   ├── index.html
│   ├── jest.config.ts
│   ├── package.json
│   ├── release.config.js
│   ├── tsconfig.json
│   ├── tsconfig.node.json
│   └── vite.config.ts
├── packages
│   ├── eslint-config
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   ├── jest.js
│   │   └── package.json
│   ├── prettier-config
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   └── package.json
│   ├── release-config
│   │   ├── .eslintrc.js
│   │   ├── .prettierrc
│   │   ├── index.js
│   │   └── package.json
│   ├── shared
│   │   ├── src
│   │   └── package.json
│   └── stylelint-config
│   ├── .eslintrc.js
│   ├── .prettierrc
│   ├── index.js
│   └── package.json
├── .commitlintrc.json
├── .gitignore
├── .nvmrc
├── package-lock.json
├── package.json
└── turbo.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment