Closed6
モノレポ採用時のconfig系の管理メモ
![kobo](https://res.cloudinary.com/zenn/image/fetch/s--j9N2IvaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/97c45c6404.jpeg)
モノレポ構成を取るときにeslintの設定やtsconfig、storybookやjestの設定を共通化したい
毎回構築するのが面倒なのでメモ
どこかのタイミングでちゃんとテンプレート化したい
![kobo](https://res.cloudinary.com/zenn/image/fetch/s--j9N2IvaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/97c45c6404.jpeg)
ESLint
packages/shared-eslint
packages/shared-eslint/package.json
{
"name": "@shared/eslint-plugin",
"version": "1.0.0",
"license": "UNLICENSED",
"private": true,
"main": "index.js",
"type": "commonjs",
"dependencies": {
"@typescript-eslint/eslint-plugin": "^6.5.0",
"eslint": "8.48.0",
"eslint-config-next": "13.4.19",
"eslint-config-prettier": "9.0.0",
"eslint-config-turbo": "1.10.12",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "7.33.2"
}
}
packages/shared-eslint/index.js
/**
* @type {import('eslint').Linter.Config'}
*/
module.exports = {
configs: {
base: {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
rules: {
'array-callback-return': 'error',
'no-await-in-loop': 'error',
'no-duplicate-imports': 'error',
'no-self-compare': 'error',
'no-template-curly-in-string': 'error',
'no-unreachable-loop': 'error',
'no-use-before-define': 'error',
'no-console': 'warn',
'eol-last': ['error', 'always'],
camelcase: 'warn',
eqeqeq: 'error',
},
},
react: {
extends: ['plugin:@shared/base', 'plugin:react/recommended'],
env: {
node: true,
},
rules: {
'react/jsx-uses-react': 'off',
'react/react-in-jsx-scope': 'off',
},
settings: {
react: {
version: 'detect',
},
},
},
next: {
extends: ['plugin:@shared/react', 'next/core-web-vitals', 'turbo'],
},
},
}
![kobo](https://res.cloudinary.com/zenn/image/fetch/s--j9N2IvaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/97c45c6404.jpeg)
Jest
packages/shared-jest
packages/shared-jest/package.json
{
"name": "@shared/jest",
"version": "1.0.0",
"license": "UNLICENSED",
"private": true,
"devDependencies": {
"@types/jest": "^29.5.4"
},
"dependencies": {
"@jest/types": "^29.6.3",
"@swc/core": "^1.3.81",
"@swc/jest": "^0.2.29",
"@testing-library/jest-dom": "^6.1.2",
"@testing-library/react": "^14.0.0",
"jest": "^29.6.4",
"jest-environment-jsdom": "^29.6.4"
}
}
packages/shared-jest/base/jest.config.ts
import type { Config } from '@jest/types'
const config: Config.InitialOptions = {
verbose: true,
testMatch: ['**/*.spec.ts', '**/*.spec.tsx'],
transformIgnorePatterns: ['/node_modules/'],
}
export default config
packages/shared-jest/react/jest.config.ts
import type { Config } from '@jest/types'
import type { Config as SWCConfig } from '@swc/core'
import baseConfig from '../base/jest.config'
const swcConfig: SWCConfig = {
sourceMaps: true,
module: {
type: 'commonjs',
},
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
},
transform: {
react: {
runtime: 'automatic',
},
},
},
}
const config: Config.InitialOptions = {
...baseConfig,
testEnvironment: 'jest-environment-jsdom',
transform: {
'^.+\\.tsx?$': [
'@swc/jest',
swcConfig as unknown as Record<string, unknown>,
],
},
}
export default config
packages/shared-jest/react/jest.setup.ts
import '@testing-library/jest-dom'
![kobo](https://res.cloudinary.com/zenn/image/fetch/s--j9N2IvaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/97c45c6404.jpeg)
Storybook
packages/shared-storybook
packages/shared-storybook/package.json
{
"name": "@shared/storybook",
"version": "1.0.0",
"license": "UNLICENSED",
"private": true,
"scripts": {
"lint": "eslint ."
},
"dependencies": {
"@shared/eslint-plugin": "*",
"@shared/tsconfig": "*",
"@storybook/addon-interactions": "^7.4.0",
"@storybook/react": "^7.4.0",
"@storybook/react-vite": "^7.4.0",
"@types/node": "^20.5.7",
"storybook": "^7.4.0"
},
"devDependencies": {
"@storybook/types": "^7.4.0"
}
}
packages/shared-storybook/tsconfig.json
{
"extends": "@shared/tsconfig/node/tsconfig.json",
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
packages/shared-storybook/preview.ts
import type { Preview } from "@storybook/react";
const preview: Preview = {
parameters: {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
};
export default preview;
packages/shared-storybook/main/base.ts
import type { StorybookConfig } from '@storybook/types'
export const config: StorybookConfig = {
stories: [],
addons: [
'@storybook/addon-docs',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-onboarding',
'@storybook/addon-interactions',
],
docs: {
autodocs: 'tag',
},
}
packages/shared-storybook/main/react.ts
import type { StorybookConfig } from "@storybook/react-vite";
import { config as baseConfig } from "./base";
export const config: StorybookConfig = {
stories: [],
addons: baseConfig.addons ? baseConfig.addons : [],
framework: {
name: "@storybook/react-vite",
options: {},
},
docs: baseConfig.docs ? baseConfig.docs : {},
};
packages/shared-storybook/main/with-interactions.ts
import type { StorybookConfig } from '@storybook/types'
export const withInteractions = (config: StorybookConfig) => {
return {
...config,
addons: config.addons
? [...config.addons, '@storybook/addon-interactions']
: [],
features: {
...config.features,
interactionsDebugger: true,
},
}
}
packages/shared-storybook/main/with-tailwind.ts
import type { StorybookConfig } from '@storybook/types'
export const withTailwind = (config: StorybookConfig) => {
return {
...config,
addons: config.addons
? [
...config.addons,
{
name: '@storybook/addon-postcss',
options: {
postcssLoaderOptions: {
implementation: require('postcss'),
},
},
},
]
: [],
}
}
![kobo](https://res.cloudinary.com/zenn/image/fetch/s--j9N2IvaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/97c45c6404.jpeg)
Tailwind
packages/shared-tailwind
packages/shared-tailwind/package.json
{
"name": "@shared/tailwind",
"version": "1.0.0",
"license": "UNLICENSED",
"private": true,
"files": [
"tailwind.config.js",
"postcss.config.js"
],
"dependencies": {
"autoprefixer": "10.4.15",
"postcss": "8.4.28",
"tailwindcss": "3.3.3"
}
}
packages/shared-tailwind/tailwind.config.ts
import type { Config } from "tailwindcss";
const config: Config = {
content: [],
theme: {
extend: {},
},
plugins: [],
};
export default config;
packages/shared-tailwind/postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
![kobo](https://res.cloudinary.com/zenn/image/fetch/s--j9N2IvaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_70/https://storage.googleapis.com/zenn-user-upload/avatar/97c45c6404.jpeg)
TSConfig
packages/shared-tsconfig
packages/shared-tsconfig/package.json
{
"name": "@shared/tsconfig",
"version": "1.0.0",
"license": "UNLICENSED",
"private": true,
"dependencies": {
"@tsconfig/create-react-app": "^2.0.1",
"@tsconfig/next": "^2.0.0",
"@tsconfig/node20": "^20.1.2",
"@tsconfig/strictest": "^2.0.1",
"typescript": "5.2.2"
}
}
packages/shared-tsconfig/base/tsconfig.json
{
"extends": [
"@tsconfig/node20/tsconfig.json",
"@tsconfig/strictest/tsconfig.json"
]
}
packages/shared-tsconfig/react/tsconfig.json
{
"extends": [
"../node/tsconfig.json",
"@tsconfig/create-react-app/tsconfig.json"
]
}
packages/shared-tsconfig/next/tsconfig.json
{
"extends": ["../react/tsconfig.json", "@tsconfig/next/tsconfig.json"]
}
このスクラップは2023/11/06にクローズされました