├── .about ├── CONTRIBUTING.md ├── DESIGN.md ├── en-US │ ├── CONTRIBUTING.md │ ├── DESIGN.md │ └── README.md └── use-this-template.png ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .idea ├── .gitignore ├── dprintProjectConfig.xml ├── dprintUserConfig.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jsLinters │ └── eslint.xml ├── modules.xml ├── project.iml └── vcs.xml ├── .node-version ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── apis ├── package.json └── src │ ├── index.share.d.ts │ ├── index.ts │ └── userModel.ts ├── dprint.json ├── eslint.config.mjs ├── package.json ├── packages └── utils │ ├── package.json │ ├── src │ ├── bar.browser.ts │ ├── bar.node.ts │ ├── bar.ts │ ├── index.ts │ ├── readFile.browser.ts │ └── readFile.node.ts │ └── tests │ ├── echoFooStr.ts │ ├── index.spec.ts │ ├── readFile.browser.spec.ts │ └── readFile.node.spec.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── scripts ├── echo-hi.ts └── rename-project-and-reset-author.sh ├── tsconfig.json ├── tsconfigs ├── tsconfig.base.json ├── tsconfig.browser.json ├── tsconfig.browser.spec.json ├── tsconfig.default.json ├── tsconfig.default.spec.json ├── tsconfig.node.json └── tsconfig.node.spec.json ├── vitest.config.ts ├── vitest.workspace.ts └── website ├── index.html ├── package.json ├── src ├── index.share.d.ts ├── index.ts └── main.ts └── vite.config.ts /.about/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 如何参与贡献 2 | 3 | TODO... 4 | -------------------------------------------------------------------------------- /.about/DESIGN.md: -------------------------------------------------------------------------------- 1 | # 设计思路 2 | 3 | ## 引 4 | 5 | [Monorepo 中基建最关键的部分是如何清晰简单的去定义相互依赖关系。](https://monorepo.tools/#what-is-a-monorepo) 6 | 7 | ## 面对的问题 8 | 9 | 开发环境往往是复杂且多样的,比如说: 10 | 11 | - 解耦了的部分需要或者可以单独发布的代码:核心、工具、统一定义等 12 | - 通过组合而形成的各种不同情况上层应用:前端 web 界面、后端服务、命令行工具等 13 | - 与工作空间存在一定依赖关系,为了发布同步和维护方便等目的放在一个仓库中进行维护:文档、脚本等 14 | 15 | 在很多的知名大型项目中他们都采取了 Monorepo 的方式进行管理,但是纵观如此多的项目,他们在一些开发体验上并没有做到极致。我们会面对各种各样的问题: 16 | 17 | - tsconfig 配置维护困难 18 | - 方案不够标准导致依赖外部插件 19 | - 全局的 alias 导致对内部幽灵依赖的检查失效 20 | - 源码跳转失效 21 | - 无法细化导出规则:屏蔽、子路径、禁用等 22 | 23 | 这些问题的根因都是因为我们没有一个统一的标准在这些不同的系统之间将他们的联系起来,而现在!我们有了。 24 | 25 | ## 可用的手段 26 | 27 | 那么在这个全新的时代我们有什么新手段可以解决我们在 Monorepo 开发过程中遇到的各式各样的问题呢? 28 | 29 | - [`exports`](https://nodejs.org/api/packages.html#exports)、[`imports`](https://nodejs.org/api/packages.html#imports)、[`conditions`](https://nodejs.org/api/packages.html#conditional-exports) 等导出特性的支持 30 | - `tsconfig` 的 [`references`](https://www.typescriptlang.org/docs/handbook/project-references.html) 提供了对不同类型文件的编译参数控制 31 | - `tsconfig` 的 [`compilerOptions.moduleResolution`](https://www.typescriptlang.org/tsconfig/moduleResolution.html) 支持了 [bundler](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#--moduleresolution-bundler) 32 | - `tsconfig` 的 [`customCondtions`](https://www.typescriptlang.org/tsconfig/#customConditions) 支持了条件导出,可以让用户根据自己的环境使用不同的导出策略 33 | - `vitest` 对于[工作空间](https://vitest.dev/guide/workspace)的支持 34 | - `yarn` 的 [Cross-references](https://yarnpkg.com/features/workspaces#cross-references)、`pnpm` 的 [Workspace protocol](https://pnpm.io/workspaces#workspace-protocol-workspace) 解决工作空间中的依赖管理问题 35 | - 基于 `rollup` 在工作空间的新型构建工具 [jiek](https://github.com/NWYLZW/jiek/blob/master/packages/jiek/README.md) 36 | 37 | ## 具体设计 38 | 39 | 首先从多个角度对我们的 Monorepo 进行规划: 40 | 41 | - 更准确更可靠更具备扩展性的类型 42 | - 按照文件类型对单元测试进行分类配置 43 | - 基于工作空间的依赖以及导出规则而自然而然的构建发布工具和方式 44 | - 基于 antfu 的 eslint 工具,你可以很简单的定义不同类型文件的校验规则 45 | 46 | ### 类型 47 | 48 | 首先我们对**类型体系**内的依赖模块解析按照我们的需要进行了更体系更具备扩展性的规划,以标准的方式来满足我们实际的开发需求,而不需要去使用非标的手段去完成我们的开发需要。 49 | 50 | 在这里我们先来看看我们是如何将我们代码归类的: 51 | 52 | - 运行在浏览器 53 | 54 | 对于这种情况,假设大部分用户正在使用 Bundler 工具:Webpack、Vite 等对自己的代码进行开发。 55 | 56 | - `.browser.ts` 结尾以及 website 目录下为浏览器环境 57 | - `.browser.spec.ts` 结尾的为模拟浏览器环境 58 | - 使用 `moduleResolution: bundler` 激活 bundler 场景下的导出策略 59 | - 添加 `browser` 的 conditional 用于激活特定的 export,针对于浏览器环境你还有需要的 conditional 可以自行添加 60 | - 添加 `dom` 的 lib 用于激活浏览器环境下的类型支持,如果你有其他的需求,可以自行添加 61 | 62 | - 运行在 Node.js 63 | 64 | Node.js 环境本项目使用了 `esbuild-register` 进行编译,所以并没有具体的 bundler,但是因为这里我们选择了 Vitest 作为测试工具,而 Vitest 恰恰基于 Vite,所以关于单元测试实际上是基于 bundler 的。 65 | 66 | 不过虽然我们的直接运行的 ts 并没有 bundler,但是实际上来说 Node.js 18 已经支持了 `exports` 的特性,所以我们可以通过 `exports` 来进行导出。 67 | 68 | - 配置、脚本文件,比如 `vitest.config.ts` 等。这些文件实际上的运行环境是 Node.js,所以这里我们也分类为该运行时 69 | - `.node.ts` 结尾以及 apis 目录下为 Node.js 环境 70 | - `.node.spec.ts` 结尾的为测试环境 71 | - 添加 `node` 的 conditional 用于激活特定的 export,针对于 Node.js 环境你还有需要的 conditional 可以自行添加 72 | 73 | - 俩者皆可运行 74 | 75 | - 有些代码可能会在浏览器和 Node.js 环境下都会运行,对于不满足上述规则的都可以归类于此。 76 | - 有些非运行时的代码,比如说我们项目中需要共用的类型信息,这部分可能在前端和后端都需要使用,但是并不需要存在相应的运行时约束。这个时候我们可以只共享相应的类型数据而不抽象单独的包或者说模块,这样可以拥有一个更轻量级的兼容层。 77 | 78 | 出于上述设计,我们就可以按照不同的文件命名规则来划分不同 tsconfig,决定不同的 `compilerOptions`,同时采用不同的条件导出配置使我们在对应文件时能 resolve 到不同的文件路径。 79 | 80 | ### 构建与发布 81 | 82 | 当我们在 Monorepo 下面进行工作的时候,一个很关键的点就是管理有什么需要构建,以及建立包之间的依赖关系。所以我们需要几个元数据: 83 | 84 | - 定义构建入口,甚至根据一些隐式条件自然而然的控制编译参数 85 | - 定义使用入口,直接与 `exports` 进行映射,开发阶段跳转定义的时候可以直接跳转到源码 86 | - 定义依赖关系,决定什么东西需要 bundle 到产物中,什么是外部依赖 87 | - 定义内部的路径重写,简化跨层级的路径引入 88 | 89 | 在这里我们充分利用了标准中的字段来进行了设计,在下面我以下面的例子简单进行说明: 90 | ```json 91 | { 92 | "name": "c", 93 | // 构建入口与使用入口实际上是同构的 94 | // 我们在开发阶段可以将源码直接设置为入口点,然后按照对应的规则在编译与发布的阶段转化到我们的产物模式 95 | "exports": { 96 | // 设置根入口 97 | ".": "./src/index.ts", 98 | "./foo": { 99 | // 当我们的 esm 和 CommonJS 的入口因为一些设计原因导致不一致时,我们可以使用 import 与 require 来进行区分 100 | // 比如说我们希望 CommonJS 被使用的时候不需要 `require('c').default` 101 | "import": "./src/foo.mts", 102 | "require": "./src/foo.ts" 103 | }, 104 | // 支持 glob 匹配递归下的整个目录树 105 | "./bar/*": "./src/bar/*.ts", 106 | "./bor": { 107 | // 假设你正在写一个组件库,你喜欢用户可以可选的引入带样式,亦或是不带样式的产物 108 | // 你可以分流为俩个入口,让用户通过 conditional 来控制 109 | "styless": "./src/bor.styless.ts", 110 | "default": "./src/bor.ts" 111 | } 112 | }, 113 | "imports": { 114 | // 类似于你在 `tsconfig.compilerOptions.paths` 中写 `"@/*": ["./src/*"]` 115 | "#/*": "./src/*", 116 | "#internal/*": "./src/internal/*" 117 | }, 118 | // 本字段中声明的均不会打包到产物中而是作为外部依赖被引用 119 | "dependencies": { 120 | // 通过 workspace 协议定义的工作空间依赖 121 | // 可以使你不需要再在当前目录创建 tsconfig 定义 references 来重复定义依赖关系 122 | // 同时在发布时也会自动将内容替换为工作空间下对应 123 | "a": "workspace:^", 124 | "foo": "^0.1.0" 125 | }, 126 | // 开发依赖如果在项目实际使用的过程中被引入了,由于相应的安装特性,内容会被打包到产物之中 127 | "devDependencies": { 128 | "b": "workspace:^", 129 | "bar": "^0.1.0" 130 | }, 131 | // 与 devDependencies 一致 132 | "optionalDependecies": {} 133 | } 134 | ``` 135 | 136 | 按照你的需求定义好如上的配置,如果没有特殊的需求,我们就不需要写任何相关的编译配置而可以直接通过相关的指令进行编译以及发布,极大地简化了配置文件的编写。 137 | 138 | ### 工具链 139 | 140 | - Tests: [Vitest](https://vitest.dev/) 141 | 142 | 配置文件位置 `vitest.workspace.ts` 和 `vitest.config.ts`。 143 | 144 | 通过使用 Vitest 的 workspace ,我们可以对测试进行类型的划分,而我们在上面的定义分类的 tsconfig 又很好的契合了这个用法,我们可以直接通过 tsconfig 而直接生成我们的配置。 145 | 146 | - Linter: [ESLint](https://eslint.org/) 147 | 148 | 这里使用 @antfu/eslint-config 作为默认配置,你可以使用 `pnpm dlx @antfu/eslint-config@latest` 调整为你需要的具体项目配置。 149 | 150 | 配置文件位置 `eslint.config.mjs`。 151 | 152 | - Formatter: [Dprint](https://dprint.dev/) 153 | 154 | 这里默认安装与配置了 typescript、json、markdown、toml、css 以及其他的 css 预编译语言的插件,如果有需要可以自行删除安装。 155 | 156 | 配置文件位置 `dprint.json`。 157 | 158 | ## Q&A 159 | 160 | - Q: 为什么不用 tsconfig paths? 161 | - A: 有多点: 162 | - 不够标准为主要原因,由此导致很多 bundler 工具并不默认支持,因此需要用户根据自己的 bundler 去安装相应的插件。 163 | - 在 monorepo 的环境下,如果使用 paths 且存在多份 tsconfig,那么你还需要告诉你的打包器应该用哪个 tsconfig,这样会导致你的打包器的配置变得复杂。 164 | - 没办法利用 conditional exports、imports。导致在部分较为常见场景处理起来不好用,比如无法使用一个路径,根据具体的文件选择不同内容导出。 165 | - 在 monorepo 环境下,如果 tsconfig 的配置复杂,每一个包可能都需要一个 tsconfig,或者有部分包需要一个特殊的 tsconfig,但是 paths 或者 rootdir 或者其他影响路径的配置,都会导致你的 paths 要在每一个这样的场景下复制一遍。 166 | 167 | - Q: 为什么将单元测试单独分开? 168 | - A: 类型污染,单元测试往往会依赖 @types/node 这间接导致你包括了单元测试文件的 tsconfig project 都会被 node 的类型污染,以及其他的类型污染。 169 | 170 | 参考资料:[Ambient Module Declaration](https://www.typescriptlang.org/docs/handbook/modules/reference.html#:~:text=Ambient%20modules.%20TypeScript%20supports%20a%20syntax%20in%20script) 171 | 172 | - Q: 为什么不弄多个 tsconfig 在每个包下面? 173 | 174 | - A: 会导致维护起来十分的困难,如果你有在大型 Monorepo 下面工作的经验,你很容易遇到以下一些情况: 175 | - 每个包下面反复去[配置相同](https://github.com/web-infra-dev/rspack/blob/0db8b9441a8bf9447ce11cc69292df773482cec8/packages/rspack-cli/tsconfig.json#L3-L9)的 tsconfig 编译参数 176 | - 哪怕你在 package.json 下面已经声明了当前包的工作空间内的依赖,你同样还是需要在包下面 tsconfig 中[引用对应 project 的目录](https://github.com/volarjs/volar.js/blob/bfa90aec50b975189f574b47affb619b9e1d679d/packages/language-server/tsconfig.json#L5-L8),才能获取到依赖正确的类型 177 | 178 | 当依赖关系变多变复杂的时候,你的每一个包都需要同时维护俩套依赖定义方式,这显然是不够优雅的。 179 | 180 | - Q: 为什么要有那么多的 tsconfig? 181 | 182 | - A: 已经很少了。对于一个现代化并完善的前端项目来说,我们必然有几个核心需求 183 | - 写 Bundler(Webpack, Rollup, Vite) 的配置文件 184 | - 写运行在浏览器的前端项目文件 185 | - 写不限制使用范围的文件 186 | - 写单元测试文件 187 | 188 | 这些并不单单是一个简单的依赖管理就能把所有的问题解决,我们同时还需要认知每一种文件都有自己特定的环境类型,以及文件的模块引入策略条件,乃至于编译选项的配置。所以我们至少需要 3 * 2 个不同的 tsconfig 来管理这些文件。 189 | 190 | ## 相关 191 | 192 | 一些朋友在看了本项目后推荐的一些相关资料(没想到也有和我有着类似思考方式的): 193 | 194 | - [tshy](https://github.com/isaacs/tshy) 195 | - [TypeScript Monorepo 的多种实践方式](https://github.com/colinhacks/live-typescript-monorepo) 196 | - [Esbuild 中的 project reference 实践方式](https://github.com/evanw/esbuild/issues/1250#issuecomment-1463826174) 197 | 198 | 参考资料: 199 | 200 | - [Monorepo tools](https://monorepo.tools/) 201 | - [Monorepo vs. polyrepo](https://github.com/joelparkerhenderson/monorepo-vs-polyrepo) 202 | - [Monorepo ≠ is different fromMonolith](https://blog.nrwl.io/misconceptions-about-monorepos-monorepo-monolith-df1250d4b03c) 203 | - [Node.js 中的条件导出](https://nodejs.org/api/packages.html#conditional-exports) 204 | - [TypeScript 中的模块解析策略](https://www.typescriptlang.org/docs/handbook/modules/reference.html#the-moduleresolution-compiler-option) 205 | 206 | ## 未来 207 | 208 | - 自动化体系的完善 209 | - 发包 210 | - 部署 211 | - 优化任务流 212 | 213 | 根据目标的依赖关系进行构建任务规划,从而避免整体构建的性能困境与手动规划任务困难的难点 214 | - 不再依赖任何的 PM 工具 215 | -------------------------------------------------------------------------------- /.about/en-US/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | TODO... 4 | -------------------------------------------------------------------------------- /.about/en-US/DESIGN.md: -------------------------------------------------------------------------------- 1 | # 设计思路 2 | 3 | 出于社区环境对 `exports`、`conditions` 等新特性的支持,我们已经可以使用一套全新的方式去架构我们的 monorepo 项目。 4 | 5 | 基于以下几点: 6 | 7 | - 通过 `tsconfig.json` 的 `references` 来管理不同类型文件的类型相关规则 8 | - 针对于多样化包出口的需求,可采用 `exports` 配合支持的 condition 来实现 9 | - 同时对于不同的测试需求,这里也通过 tsconfig 中的相关约束进行配置生成 10 | 11 | 如此便能实现我们的全新的设计思路。 12 | 13 | ## 项目规范 14 | 15 | 本项目指在对**类型系统**进行规范借鉴,故在技术栈的选型上主要为示范性作用,很多工具链的配置改造成本较低,如果你需要进行自己的技术选型,建议开发过程中按照相应的规则进行调整。 16 | 17 | ### 项目结构 18 | 19 | 本项目侧重于类型系统如何在 monorepo 中进行管理,首先我们看到 `tsconfigs` 目录,我们从不同种类的文件进行划分: 20 | 21 | - 运行在浏览器 22 | 23 | 对于这种情况,假设大部分用户正在使用 Bundler 工具:Webpack、Vite 等对自己的代码进行开发。 24 | 25 | - `.browser.ts` 结尾以及 website 目录下为浏览器环境 26 | - `.browser.spec.ts` 结尾的为模拟浏览器环境 27 | - 使用 `moduleResolution: bundler` 激活 bundler 场景下的导出策略 28 | - 添加 `browser` 的 conditional 用于激活特定的 export,针对于浏览器环境你还有需要的 conditional 可以自行添加 29 | - 添加 `dom` 的 lib 用于激活浏览器环境下的类型支持,如果你有其他的需求,可以自行添加 30 | 31 | - 运行在 Node.js 32 | 33 | Node.js 环境本项目使用了 `esbuild-register` 进行编译,所以并没有具体的 bundler,但是因为这里我们选择了 Vitest 作为测试工具,而 Vitest 恰恰基于 Vite,所以关于单元测试实际上是基于 bundler 的。 34 | 35 | 不过虽然我们的直接运行的 ts 并没有 bundler,但是实际上来说 Node.js 18 已经支持了 `exports` 的特性,所以我们可以通过 `exports` 来进行导出。 36 | 37 | - 配置、脚本文件,比如 `vitest.config.ts` 等。这些文件实际上的运行环境是 Node.js,所以这里我们也分类为该运行时 38 | - `.node.ts` 结尾以及 apis 目录下为 Node.js 环境 39 | - `.node.spec.ts` 结尾的为测试环境 40 | - 添加 `node` 的 conditional 用于激活特定的 export,针对于 Node.js 环境你还有需要的 conditional 可以自行添加 41 | 42 | - 俩者皆可运行 43 | 44 | - 有些代码可能会在浏览器和 Node.js 环境下都会运行,对于不满足上述规则的都可以归类于此。 45 | - 有些非运行时的代码,比如说我们项目中需要共用的类型信息,这部分可能在前端和后端都需要使用,但是并不需要存在相应的运行时约束。这个时候我们可以只共享相应的类型数据而不抽象单独的包或者说模块,这样可以拥有一个更轻量级的兼容层。 46 | 47 | 出于上述考量,我们就可以按照不同的文件命名规则来划分不同 tsconfig,其次在包中导出依赖的时候根据导出文件的使用范围,合理采用不同的条件导出。 48 | 49 | ### 工具链 50 | 51 | - Linter: [ESLint](https://eslint.org/) 52 | 53 | 这里使用 @antfu/eslint-config 作为默认配置,你可以使用 `pnpm dlx @antfu/eslint-config@latest` 调整为你需要的具体项目配置。 54 | 55 | 配置文件位置 `eslint.config.mjs`。 56 | 57 | - Formatter: [Dprint](https://dprint.dev/) 58 | 59 | 这里默认安装与配置了 typescript、json、markdown、toml、css 以及其他的 css 预编译语言的插件,如果有需要可以自行删除安装。 60 | 61 | 配置文件位置 `dprint.json`。 62 | 63 | ## Q&A 64 | 65 | Q: 为什么不用 tsconfig paths? 66 | 67 | A: 有多点: 68 | - 不够标准为主要原因,由此导致很多 bundler 工具并不默认支持,因此需要用户根据自己的 bundler 去安装相应的插件。 69 | - 在 monorepo 的环境下,如果使用 paths 且存在多份 tsconfig,那么你还需要告诉你的打包器应该用哪个 tsconfig,这样会导致你的打包器的配置变得复杂。 70 | - 没办法利用 conditional exports、imports。导致在部分较为常见场景处理起来不好用,比如无法使用一个路径,根据具体的文件选择不同内容导出。 71 | - 在 monorepo 环境下,如果 tsconfig 的配置复杂,每一个包可能都需要一个 tsconfig,或者有部分包需要一个特殊的 tsconfig,但是 paths 或者 rootdir 或者其他影响路径的配置,都会导致你的 paths 要在每一个这样的场景下复制一遍。 72 | 73 | Q: 为什么将单元测试单独分开? 74 | 75 | A: 类型污染,单元测试往往会依赖 @types/node 这间接导致你包括了单元测试文件的 tsconfig project 都会被 node 的类型污染,以及其他的类型污染。 76 | 77 | 参考资料:[Ambient Module Declaration](https://www.typescriptlang.org/docs/handbook/modules/reference.html#:~:text=Ambient%20modules.%20TypeScript%20supports%20a%20syntax%20in%20script) 78 | 79 | Q: 为什么不弄多个 tsconfig 在每个包下面? 80 | 81 | A: 麻烦,你要写多个,然后不断的 extends,维护成本也很高。不是一种好的实践。 82 | 83 | Q: 为什么要有那么多的 tsconfig? 84 | 85 | A: 对于一个现代化并完善的前端项目来说,我们必然有几个核心需求 86 | 87 | - 写 Bundler(Webpack, Rollup, Vite) 的配置文件 88 | - 写运行在浏览器的前端项目文件 89 | - 写不限制使用范围的文件 90 | - 写单元测试文件 91 | 92 | 这些并不单单是一个简单的依赖管理就能把所有的问题解决,我们同时还需要认知每一种文件都有自己特定的环境类型,以及文件的模块引入策略条件,乃至于编译选项的配置。所以我们至少需要 3 * 2 个不同的 tsconfig 来管理这些文件。 93 | 94 | ## 相关 95 | 96 | 一些朋友在看了本项目后推荐的一些相关资料(没想到也有和我有着类似思考方式的): 97 | 98 | - [tshy](https://github.com/isaacs/tshy) 99 | - [TypeScript Monorepo 的多种实践方式](https://github.com/colinhacks/live-typescript-monorepo) 100 | - [Esbuild 中的 project reference 实践方式](https://github.com/evanw/esbuild/issues/1250#issuecomment-1463826174) 101 | 102 | 参考资料: 103 | 104 | - [Node.js 中的条件导出](https://nodejs.org/api/packages.html#conditional-exports) 105 | - [TypeScript 中的模块解析策略](https://www.typescriptlang.org/docs/handbook/modules/reference.html#the-moduleresolution-compiler-option) 106 | -------------------------------------------------------------------------------- /.about/en-US/README.md: -------------------------------------------------------------------------------- 1 | # TypeScript Web Monorepo Template 2 | 3 | | en-US | [zh-Hans](../../README.md) | 4 | 5 | A template project for rapid development of web applications under a monorepo architecture. 6 | 7 | ## Learn Project 8 | 9 | - [Design](./DESIGN.md) 10 | - [How to contribute](./CONTRIBUTING.md) 11 | - [Code of conduct](../../CODE_OF_CONDUCT.md) 12 | -------------------------------------------------------------------------------- /.about/use-this-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NWYLZW/ts-web-monorepo-template/74dde9c6b55cfc16cca426976b9bba9c4c0b502c/.about/use-this-template.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | 3 | *.png -text 4 | *.jpg -text 5 | *.ico -text 6 | *.gif -text 7 | *.webp -text 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Node template 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | .pnpm-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # Snowpack dependency directory (https://snowpack.dev/) 47 | web_modules/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Optional stylelint cache 59 | .stylelintcache 60 | 61 | # Microbundle cache 62 | .rpt2_cache/ 63 | .rts2_cache_cjs/ 64 | .rts2_cache_es/ 65 | .rts2_cache_umd/ 66 | 67 | # Optional REPL history 68 | .node_repl_history 69 | 70 | # Output of 'npm pack' 71 | *.tgz 72 | 73 | # Yarn Integrity file 74 | .yarn-integrity 75 | 76 | # dotenv environment variable files 77 | .env 78 | .env.development.local 79 | .env.test.local 80 | .env.production.local 81 | .env.local 82 | 83 | # parcel-bundler cache (https://parceljs.org/) 84 | .cache 85 | .parcel-cache 86 | 87 | # Next.js build output 88 | .next 89 | out 90 | 91 | # Nuxt.js build / generate output 92 | .nuxt 93 | dist 94 | 95 | # Gatsby files 96 | .cache/ 97 | # Comment in the public line in if your project uses Gatsby and not Next.js 98 | # https://nextjs.org/blog/next-9-1#public-directory-support 99 | # public 100 | 101 | # vuepress build output 102 | .vuepress/dist 103 | 104 | # vuepress v2.x temp and cache directory 105 | .temp 106 | .cache 107 | 108 | # Docusaurus cache and generated files 109 | .docusaurus 110 | 111 | # Serverless directories 112 | .serverless/ 113 | 114 | # FuseBox cache 115 | .fusebox/ 116 | 117 | # DynamoDB Local files 118 | .dynamodb/ 119 | 120 | # TernJS port file 121 | .tern-port 122 | 123 | # Stores VSCode versions used for testing VSCode extensions 124 | .vscode-test 125 | 126 | # yarn v2 127 | .yarn/cache 128 | .yarn/unplugged 129 | .yarn/build-state.yml 130 | .yarn/install-state.gz 131 | .pnp.* 132 | 133 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /.idea/dprintProjectConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /.idea/dprintUserConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/jsLinters/eslint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/project.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | v22.11.0 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "gplane.dprint2", 4 | "dprint.dprint" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch website progress", 9 | "type": "node", 10 | "request": "launch", 11 | "runtimeExecutable": "pnpm", 12 | "runtimeArgs": ["--filter", "website", "start"], 13 | "skipFiles": [ 14 | "/**" 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | 4 | // Disable the default formatter, use eslint instead 5 | "prettier.enable": false, 6 | "editor.formatOnSave": false, 7 | 8 | // Auto fix 9 | "editor.codeActionsOnSave": { 10 | "source.fixAll.eslint": "explicit", 11 | "source.organizeImports": "never" 12 | }, 13 | 14 | "eslint.options": { 15 | "flags": ["unstable_ts_config"] 16 | }, 17 | 18 | "eslint.runtime": "node", 19 | 20 | // Silent the stylistic rules in you IDE, but still auto fix them 21 | "eslint.rules.customizations": [ 22 | { "rule": "style/*", "severity": "off", "fixable": true }, 23 | { "rule": "format/*", "severity": "off", "fixable": true }, 24 | { "rule": "*-indent", "severity": "off", "fixable": true }, 25 | { "rule": "*-spacing", "severity": "off", "fixable": true }, 26 | { "rule": "*-spaces", "severity": "off", "fixable": true }, 27 | { "rule": "*-order", "severity": "off", "fixable": true }, 28 | { "rule": "*-dangle", "severity": "off", "fixable": true }, 29 | { "rule": "*-newline", "severity": "off", "fixable": true }, 30 | { "rule": "*quotes", "severity": "off", "fixable": true }, 31 | { "rule": "*semi", "severity": "off", "fixable": true } 32 | ], 33 | 34 | // Enable eslint for all supported languages 35 | "eslint.validate": [ 36 | "javascript", 37 | "javascriptreact", 38 | "typescript", 39 | "typescriptreact", 40 | "vue", 41 | "html", 42 | "markdown", 43 | "json", 44 | "json5", 45 | "jsonc", 46 | "yaml", 47 | "toml", 48 | "xml", 49 | "gql", 50 | "graphql", 51 | "astro", 52 | "css", 53 | "less", 54 | "scss", 55 | "pcss", 56 | "postcss" 57 | ], 58 | "editor.defaultFormatter": "gplane.dprint2", 59 | 60 | "search.exclude": { 61 | "**/*.snap": true, 62 | "**/*.svg": true, 63 | "**/.git": true, 64 | "**/.github": false, 65 | "**/.nuxt": true, 66 | "**/.output": true, 67 | "**/.pnpm": true, 68 | "**/.vscode": true, 69 | "**/.yarn": true, 70 | "**/assets": true, 71 | "**/bower_components": true, 72 | "**/dist/**": true, 73 | "**/logs": true, 74 | "**/node_modules": true, 75 | "**/out/**": true, 76 | "**/package-lock.json": true, 77 | "**/pnpm-lock.yaml": true, 78 | "**/public": true, 79 | "**/temp": true, 80 | "**/yarn.lock": true, 81 | "**/CHANGELOG*": true, 82 | "**/LICENSE*": true 83 | }, 84 | 85 | // ========== File Nesting ========== 86 | // this might not be up to date with the repo, please check yourself 87 | // https://github.com/antfu/vscode-file-nesting-config 88 | "explorer.fileNesting.enabled": true, 89 | "explorer.fileNesting.expand": false, 90 | "explorer.fileNesting.patterns": { 91 | "*.asax": "$(capture).*.cs, $(capture).*.vb", 92 | "*.ascx": "$(capture).*.cs, $(capture).*.vb", 93 | "*.ashx": "$(capture).*.cs, $(capture).*.vb", 94 | "*.aspx": "$(capture).*.cs, $(capture).*.vb", 95 | "*.bloc.dart": "$(capture).event.dart, $(capture).state.dart", 96 | "*.c": "$(capture).h", 97 | "*.cc": "$(capture).hpp, $(capture).h, $(capture).hxx", 98 | "*.cjs": "$(capture).cjs.map, $(capture).*.cjs, $(capture)_*.cjs", 99 | "*.component.ts": "$(capture).component.html, $(capture).component.spec.ts, $(capture).component.css, $(capture).component.scss, $(capture).component.sass, $(capture).component.less", 100 | "*.cpp": "$(capture).hpp, $(capture).h, $(capture).hxx", 101 | "*.cs": "$(capture).*.cs", 102 | "*.cshtml": "$(capture).cshtml.cs", 103 | "*.csproj": "*.config, *proj.user, appsettings.*, bundleconfig.json", 104 | "*.css": "$(capture).css.map, $(capture).*.css", 105 | "*.cxx": "$(capture).hpp, $(capture).h, $(capture).hxx", 106 | "*.dart": "$(capture).freezed.dart, $(capture).g.dart", 107 | "*.ex": "$(capture).html.eex, $(capture).html.heex, $(capture).html.leex", 108 | "*.go": "$(capture)_test.go", 109 | "*.java": "$(capture).class", 110 | "*.js": "$(capture).js.map, $(capture).*.js, $(capture)_*.js", 111 | "*.jsx": "$(capture).js, $(capture).*.jsx, $(capture)_*.js, $(capture)_*.jsx", 112 | "*.master": "$(capture).*.cs, $(capture).*.vb", 113 | "*.mjs": "$(capture).mjs.map, $(capture).*.mjs, $(capture)_*.mjs", 114 | "*.module.ts": "$(capture).resolver.ts, $(capture).controller.ts, $(capture).service.ts", 115 | "*.pubxml": "$(capture).pubxml.user", 116 | "*.resx": "$(capture).*.resx, $(capture).designer.cs, $(capture).designer.vb", 117 | "*.tex": "$(capture).acn, $(capture).acr, $(capture).alg, $(capture).aux, $(capture).bbl, $(capture).blg, $(capture).fdb_latexmk, $(capture).fls, $(capture).glg, $(capture).glo, $(capture).gls, $(capture).idx, $(capture).ind, $(capture).ist, $(capture).lof, $(capture).log, $(capture).lot, $(capture).out, $(capture).pdf, $(capture).synctex.gz, $(capture).toc, $(capture).xdv", 118 | "*.ts": "$(capture).js, $(capture).d.ts.map, $(capture).*.ts, $(capture)_*.js, $(capture)_*.ts", 119 | "*.tsx": "$(capture).ts, $(capture).*.tsx, $(capture)_*.ts, $(capture)_*.tsx", 120 | "*.vbproj": "*.config, *proj.user, appsettings.*, bundleconfig.json", 121 | "*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue", 122 | "*.xaml": "$(capture).xaml.cs", 123 | "+layout.svelte": "+layout.ts,+layout.ts,+layout.js,+layout.server.ts,+layout.server.js,+layout.gql", 124 | "+page.svelte": "+page.server.ts,+page.server.js,+page.ts,+page.js,+page.gql", 125 | ".clang-tidy": ".clang-format, .clangd, compile_commands.json", 126 | ".env": "*.env, .env.*, .envrc, env.d.ts", 127 | ".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*", 128 | ".project": ".classpath", 129 | "BUILD.bazel": "*.bzl, *.bazel, *.bazelrc, bazel.rc, .bazelignore, .bazelproject, WORKSPACE", 130 | "CMakeLists.txt": "*.cmake, *.cmake.in, .cmake-format.yaml, CMakePresets.json", 131 | "I*.cs": "$(capture).cs", 132 | "artisan": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, server.php, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, webpack.mix.js, windi.config.*", 133 | "astro.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 134 | "cargo.toml": ".clippy.toml, .rustfmt.toml, cargo.lock, clippy.toml, cross.toml, rust-toolchain.toml, rustfmt.toml", 135 | "composer.json": ".php*.cache, composer.lock, phpunit.xml*, psalm*.xml", 136 | "default.nix": "shell.nix", 137 | "deno.json*": "*.env, .env.*, .envrc, api-extractor.json, deno.lock, env.d.ts, import-map.json, import_map.json, jsconfig.*, tsconfig.*, tsdoc.*", 138 | "dockerfile": ".dockerignore, docker-compose.*, dockerfile*", 139 | "flake.nix": "flake.lock", 140 | "gatsby-config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, gatsby-browser.*, gatsby-node.*, gatsby-ssr.*, gatsby-transformer.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 141 | "gemfile": ".ruby-version, gemfile.lock", 142 | "go.mod": ".air*, go.sum", 143 | "go.work": "go.work.sum", 144 | "mix.exs": ".credo.exs, .dialyzer_ignore.exs, .formatter.exs, .iex.exs, .tool-versions, mix.lock", 145 | "next.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, next-env.d.ts, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 146 | "nuxt.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 147 | "package.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*", 148 | "pubspec.yaml": ".metadata, .packages, all_lint_rules.yaml, analysis_options.yaml, build.yaml, pubspec.lock, pubspec_overrides.yaml", 149 | "pyproject.toml": ".pdm.toml, pdm.lock, pyproject.toml", 150 | "quasar.conf.js": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, quasar.extensions.json, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 151 | "readme*": "authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying, credits, governance.md, history.md, license*, maintainers, readme*, security.md, sponsors*", 152 | "remix.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, remix.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 153 | "rush.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*", 154 | "shims.d.ts": "*.d.ts", 155 | "svelte.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, houdini.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, mdsvex.config.js, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vite.config.*, vitest.config.*, webpack.config.*, windi.config.*", 156 | "vite.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 157 | "vue.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*" 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024-present YiJie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeScript Web Monorepo Template 2 | 3 | | zh-Hans | [en-US](.about/en-US/README.md) | 4 | 5 | 用于在 monorepo 架构下最现代最前沿的快速开发 web 应用的模版项目。 6 | 7 | ## 为什么用我 8 | 9 | - 轻量:未引入框架,只有最基础的工具链,可以灵活决定项目技术栈 10 | - 安全:类型系统的设计更加准确,带来的是完善的检查机制 11 | - 丰富:整理了常见的场景的最佳实践,可以很方便的根据已有内容快速扩张迭代 12 | - 现代:使用支持**最规范**也是**最前沿**的标准来决定项目的组织方式 13 | - 易用:提供了初始化的脚本,可以快速的为项目配置你的元信息,无需手动一个个处理 14 | - 高效:一般的 monorepo 的跨包跳转只能跳转到编译后的内容,本项目可以直接跳转到源码,极大地提高了开发效率 15 | 16 | ## 怎么用我 17 | 18 | ### 初始化 19 | 20 | 1. 点击右上角的 `Use this template` 按钮 21 | ![use-this-template.png](.about/use-this-template.png) 22 | 2. 根据提示填写你的项目信息 23 | 3. 克隆你的项目到本地 24 | 4. 运行 `./scripts/rename-project-and-reset-author.sh` 脚本,根据提示填写你的项目信息 25 | 5. 运行 `pnpm install` 安装依赖 26 | 6. 运行 `pnpm --filter website start` 启动开发服务器 27 | 28 | ### 同步 29 | 30 | TODO... 31 | 32 | ## 了解本项目 33 | 34 | - [设计](.about/DESIGN.md) 35 | - [如何参与贡献](.about/CONTRIBUTING.md) 36 | - [行为守则](./CODE_OF_CONDUCT.md) 37 | -------------------------------------------------------------------------------- /apis/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apis", 3 | "version": "0.1.0", 4 | "author": { 5 | "name": "YiJie" 6 | }, 7 | "scripts": { 8 | "start": "node -r esbuild-register src/index.ts" 9 | }, 10 | "dependencies": { 11 | "@mono/utils": "workspace:*" 12 | }, 13 | "devDependencies": { 14 | "esbuild-register": "^3.6.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /apis/src/index.share.d.ts: -------------------------------------------------------------------------------- 1 | import type { User as U0 } from './userModel' 2 | 3 | declare module '@mono/share' { 4 | export type User = U0 5 | export type Strings = 'abc' | 'def' 6 | } 7 | -------------------------------------------------------------------------------- /apis/src/index.ts: -------------------------------------------------------------------------------- 1 | import { name } from '@mono/utils/readFile' 2 | // ^? 3 | import type { Numbers, Strings } from '@mono/share' 4 | 5 | // eslint-disable-next-line no-console 6 | console.log(name) 7 | // eslint-disable-next-line no-console 8 | console.log('Hello, World!') 9 | 10 | const num: Numbers = 123 11 | // eslint-disable-next-line no-console 12 | console.log(num) 13 | const str: Strings = 'abc' 14 | // eslint-disable-next-line no-console 15 | console.log(str) 16 | -------------------------------------------------------------------------------- /apis/src/userModel.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | name: string 3 | } 4 | -------------------------------------------------------------------------------- /dprint.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript": { 3 | "quoteStyle": "preferSingle", 4 | "semiColons": "asi", 5 | "trailingCommas": "never", 6 | "conditionalType.operatorPosition": "nextLine", 7 | "jsx.multiLineParens": "never", 8 | "typeParameters.trailingCommas": "onlyMultiLine", 9 | "module.sortImportDeclarations": "caseSensitive", 10 | "module.sortExportDeclarations": "caseSensitive", 11 | "exportDeclaration.sortNamedExports": "caseSensitive", 12 | "importDeclaration.sortNamedImports": "caseSensitive", 13 | "importDeclaration.sortTypeOnlyImports": "first", 14 | "exportDeclaration.sortTypeOnlyExports": "first" 15 | }, 16 | "malva": { 17 | "ignoreCommentDirective": "dprint-ignore", 18 | "quotes": "preferSingle", 19 | "omitNumberLeadingZero": true 20 | }, 21 | "json": { 22 | }, 23 | "markdown": { 24 | }, 25 | "toml": { 26 | }, 27 | "excludes": [ 28 | "**/node_modules", 29 | "**/*-lock.json" 30 | ], 31 | "plugins": [ 32 | "https://plugins.dprint.dev/typescript-0.93.2.wasm", 33 | "https://plugins.dprint.dev/json-0.19.2.wasm", 34 | "https://plugins.dprint.dev/markdown-0.16.4.wasm", 35 | "https://plugins.dprint.dev/toml-0.6.1.wasm", 36 | "https://plugins.dprint.dev/g-plane/malva-v0.4.0.wasm", 37 | "https://plugins.dprint.dev/g-plane/markup_fmt-v0.15.1.wasm" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import config from '@antfu/eslint-config' 2 | 3 | export default config( 4 | { 5 | stylistic: false, 6 | typescript: { 7 | tsconfigPath: './tsconfig.json', 8 | overrides: { 9 | 'ts/no-namespace': 'off', 10 | 'ts/no-empty-object-type': 'off', 11 | 'ts/method-signature-style': 'off', 12 | 'ts/no-use-before-define': 'off', 13 | 'ts/ban-ts-comment': 'off', 14 | 'ts/no-wrapper-object-types': 'off', 15 | 'ts/no-unsafe-function-type': 'off', 16 | 'ts/strict-boolean-expressions': 'off', 17 | 18 | 'import/no-mutable-exports': 'off', 19 | 'perfectionist/sort-imports': 'off', 20 | 'perfectionist/sort-named-imports': 'off' 21 | } 22 | } 23 | }, 24 | // test, script and config files 25 | { 26 | files: [ 27 | 'packages/*/tests/**/*.{js,ts,tsx}', 28 | 'vitest.config.ts', 29 | 'eslint.config.mjs', 30 | 'vitest.workspace.ts', 31 | 'website/vite.config.ts', 32 | 'scripts/**/*.{js,ts}' 33 | ], 34 | rules: { 35 | 'no-console': 'off' 36 | } 37 | } 38 | ) 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-web-monorepo-template", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "packageManager": "pnpm@9.10.0", 7 | "author": { 8 | "name": "YiJie" 9 | }, 10 | "engines": { 11 | "node": ">=18.0.0", 12 | "npm": ">=999.999.999", 13 | "pnpm": ">=9.0.0", 14 | "yarn": ">=999.999.999" 15 | }, 16 | "scripts": { 17 | "postinstall": "dprint editor-info", 18 | "rename-project-and-reset-author": "./scripts/rename-project-and-reset-author.sh", 19 | "echo-hi": "node -r esbuild-register ./scripts/echo-hi.ts" 20 | }, 21 | "devDependencies": { 22 | "@antfu/eslint-config": "^3.9.2", 23 | "@types/node": "^18.19.45", 24 | "dprint": "^0.47.2", 25 | "esbuild-register": "^3.6.0", 26 | "eslint": "^9.10.0", 27 | "jiek": "^2.2.6", 28 | "rollup-plugin-esbuild": "^6.1.1", 29 | "typescript": "^5.7.2", 30 | "vitest": "^2.0.5" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mono/utils", 3 | "version": "0.1.0", 4 | "author": { 5 | "name": "YiJie" 6 | }, 7 | "exports": { 8 | "./package.json": "./package.json", 9 | ".": "./src/index.ts", 10 | "./bar": { 11 | "import": "./src/bar.browser.ts", 12 | "require": "./src/bar.node.ts", 13 | "default": "./src/bar.ts" 14 | }, 15 | "./readFile": { 16 | "node": "./src/readFile.node.ts", 17 | "browser": "./src/readFile.browser.ts" 18 | } 19 | }, 20 | "files": ["LICENSE", "README.md", "dist", "src"], 21 | "scripts": { 22 | "prepublish": "jb -nm && jk", 23 | "postpublish": "jk" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/utils/src/bar.browser.ts: -------------------------------------------------------------------------------- 1 | export * from './bar' 2 | -------------------------------------------------------------------------------- /packages/utils/src/bar.node.ts: -------------------------------------------------------------------------------- 1 | export * from './bar' 2 | -------------------------------------------------------------------------------- /packages/utils/src/bar.ts: -------------------------------------------------------------------------------- 1 | export function bar() { 2 | return 'bar' 3 | } 4 | -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@mono/utils/bar' 2 | export function foo() { 3 | return 'foo' 4 | } 5 | -------------------------------------------------------------------------------- /packages/utils/src/readFile.browser.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line ts/no-unnecessary-type-assertion 2 | export const name = 'readFile.browser' as const 3 | -------------------------------------------------------------------------------- /packages/utils/src/readFile.node.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line ts/no-unnecessary-type-assertion 2 | export const name = 'readFile.node' as const 3 | -------------------------------------------------------------------------------- /packages/utils/tests/echoFooStr.ts: -------------------------------------------------------------------------------- 1 | export function echoFooStr() { 2 | // eslint-disable-next-line no-console 3 | console.log('foo') 4 | } 5 | -------------------------------------------------------------------------------- /packages/utils/tests/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { foo } from '@mono/utils' 2 | import { describe, expect, it } from 'vitest' 3 | import { echoFooStr } from './echoFooStr' 4 | 5 | describe('mono utils', () => { 6 | it('foo', () => { 7 | echoFooStr() 8 | expect(foo()).toBe('foo') 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /packages/utils/tests/readFile.browser.spec.ts: -------------------------------------------------------------------------------- 1 | import { name } from '@mono/utils/readFile' 2 | import { describe, expect, expectTypeOf, it } from 'vitest' 3 | 4 | describe('readFile.browser', () => { 5 | it('name', () => { 6 | expect(name).toBe('readFile.browser') 7 | expectTypeOf(name).toEqualTypeOf<'readFile.browser'>() 8 | expectTypeOf(name).not.toEqualTypeOf<'readFile.node'>() 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /packages/utils/tests/readFile.node.spec.ts: -------------------------------------------------------------------------------- 1 | import { name } from '@mono/utils/readFile' 2 | import { describe, expect, expectTypeOf, it } from 'vitest' 3 | 4 | describe('readFile.node', () => { 5 | it('name', () => { 6 | expect(name).toBe('readFile.node') 7 | expectTypeOf(name).toEqualTypeOf<'readFile.node'>() 8 | expectTypeOf(name).not.toEqualTypeOf<'readFile.browser'>() 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - apis 3 | - website 4 | - packages/* 5 | -------------------------------------------------------------------------------- /scripts/echo-hi.ts: -------------------------------------------------------------------------------- 1 | console.log('hi') 2 | -------------------------------------------------------------------------------- /scripts/rename-project-and-reset-author.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # use directory name as project name and let user confirm it or input a new one 4 | echo "Enter the new project name: (default: $(basename "$(pwd)"), press Enter to use default)" 5 | read -r new_project_name 6 | new_project_name=${new_project_name:-$(basename "$(pwd)")} 7 | echo "New project name: $new_project_name" 8 | 9 | # use git config user.name as author name and let user confirm it or input a new one 10 | echo "Enter the new author name: (default: $(git config user.name), press Enter to use default)" 11 | read -r new_author_name 12 | new_author_name=${new_author_name:-$(git config user.name)} 13 | echo "New author name: $new_author_name" 14 | 15 | # replace 'mono' string in this directory all files with new_project_name 16 | grep -rl --exclude-dir={.git,node_modules} --exclude='*.md' 'mono' .\ 17 | | xargs sed -i '' -e "s/mono/$new_project_name/g" 18 | # replace 'YiJie' string in this directory all files with new_author_name 19 | grep -rl --exclude-dir={.git,node_modules} --exclude='*.md' 'YiJie' .\ 20 | | xargs sed -i '' -e "s/YiJie/$new_author_name/g" 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfigs/tsconfig.default.json" }, 5 | { "path": "./tsconfigs/tsconfig.default.spec.json" }, 6 | { "path": "./tsconfigs/tsconfig.browser.json" }, 7 | { "path": "./tsconfigs/tsconfig.browser.spec.json" }, 8 | { "path": "./tsconfigs/tsconfig.node.json" }, 9 | { "path": "./tsconfigs/tsconfig.node.spec.json" } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tsconfigs/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "rootDir": "..", 5 | "module": "ESNext", 6 | "allowImportingTsExtensions": true, 7 | "strict": true, 8 | "strictNullChecks": true, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "skipLibCheck": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tsconfigs/tsconfig.browser.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["./tsconfig.base.json"], 3 | "compilerOptions": { 4 | "composite": true, 5 | "target": "esnext", 6 | "lib": ["ES2019", "dom"], 7 | "customConditions": ["browser"], 8 | "module": "esnext", 9 | "moduleResolution": "bundler", 10 | "types": [] 11 | }, 12 | "references": [ 13 | { "path": "./tsconfig.default.json" } 14 | ], 15 | "include": [ 16 | "../apis/src/**/*.share.d.ts", 17 | "../website/src/**/*", 18 | "../website/tests/**/*", 19 | "../packages/*/src/**/*.browser.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tsconfigs/tsconfig.browser.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["./tsconfig.browser.json"], 3 | "compilerOptions": { 4 | "composite": true 5 | }, 6 | "references": [ 7 | { "path": "./tsconfig.browser.json" } 8 | ], 9 | "include": [ 10 | "../packages/*/tests/**/*.browser.ts", 11 | "../packages/*/tests/**/*.browser.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /tsconfigs/tsconfig.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["./tsconfig.base.json"], 3 | "compilerOptions": { 4 | "composite": true, 5 | "moduleResolution": "bundler" 6 | }, 7 | "include": [ 8 | "../packages/*/src/**/*.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /tsconfigs/tsconfig.default.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["./tsconfig.default.json"], 3 | "compilerOptions": { 4 | "composite": true 5 | }, 6 | "references": [ 7 | { "path": "./tsconfig.default.json" } 8 | ], 9 | "include": [ 10 | "../packages/*/tests/**/*.ts", 11 | "../packages/*/tests/**/*.spec.ts" 12 | ], 13 | "exclude": [ 14 | "../packages/*/tests/**/*.browser.ts", 15 | "../packages/*/tests/**/*.browser.spec.ts", 16 | "../packages/*/tests/**/*.node.ts", 17 | "../packages/*/tests/**/*.node.spec.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /tsconfigs/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["./tsconfig.base.json"], 3 | "compilerOptions": { 4 | "composite": true, 5 | "target": "ESNext", 6 | "customConditions": ["node"], 7 | "module": "NodeNext", 8 | "moduleResolution": "NodeNext", 9 | "resolveJsonModule": true, 10 | "types": ["node"] 11 | }, 12 | "references": [ 13 | { "path": "./tsconfig.default.json" } 14 | ], 15 | "include": [ 16 | "../scripts/**/*.ts", 17 | "../.jiek.config.ts", 18 | "../.jiek.workspace.ts", 19 | "../vitest.config.ts", 20 | "../vitest.workspace.ts", 21 | "../website/vite.config.ts", 22 | "../website/src/**/*.share.d.ts", 23 | "../apis/src/**/*", 24 | "../apis/tests/**/*", 25 | "../packages/*/src/**/*.node.ts" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /tsconfigs/tsconfig.node.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["./tsconfig.node.json"], 3 | "compilerOptions": { 4 | "composite": true 5 | }, 6 | "references": [ 7 | { "path": "./tsconfig.node.json" } 8 | ], 9 | "include": [ 10 | "../packages/*/tests/**/*.node.ts", 11 | "../packages/*/tests/**/*.node.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | }) 5 | -------------------------------------------------------------------------------- /vitest.workspace.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import path from 'node:path' 3 | import process from 'node:process' 4 | 5 | import ts from 'typescript' 6 | import { defineWorkspace } from 'vitest/config' 7 | 8 | const isTestFileGlobExpr = (expr: string) => expr.includes('.spec.') 9 | 10 | const tsconfigPath = ts.findConfigFile(process.cwd(), fs.existsSync) 11 | if (!tsconfigPath) throw new Error('tsconfig.json not found') 12 | 13 | // eslint-disable-next-line ts/no-unsafe-assignment 14 | const { config: tsconfig, error } = ts.readConfigFile(tsconfigPath, p => fs.readFileSync(p, 'utf-8')) 15 | if (error) throw error 16 | 17 | const { projectReferences } = ts.parseJsonConfigFileContent( 18 | tsconfig, 19 | ts.sys, 20 | path.dirname(tsconfigPath), 21 | {}, 22 | tsconfigPath 23 | ) 24 | 25 | const projects: { 26 | files: string[] 27 | options: ts.CompilerOptions 28 | }[] = [] 29 | projectReferences?.forEach(({ path: p }) => { 30 | // eslint-disable-next-line ts/no-unsafe-assignment 31 | const { config: tsconfig, error } = ts.readConfigFile(p, p => fs.readFileSync(p, 'utf-8')) 32 | if (error) throw error 33 | const { options, fileNames, errors } = ts.parseJsonConfigFileContent(tsconfig, ts.sys, path.dirname(p), {}, p) 34 | if (errors.length > 0) { 35 | errors.forEach(e => 36 | console.warn(`[vitest] ${typeof e.messageText === 'string' ? e.messageText : e.messageText.messageText}`) 37 | ) 38 | } 39 | if (fileNames.filter(isTestFileGlobExpr).length > 0) { 40 | projects.push({ files: fileNames, options }) 41 | } 42 | }) 43 | 44 | export default defineWorkspace(projects.map(({ 45 | files, 46 | options 47 | }) => ({ 48 | extends: './vitest.config.ts', 49 | test: { include: files }, 50 | ssr: { 51 | target: options?.customConditions?.includes('browser') 52 | ? 'webworker' 53 | : 'node' 54 | }, 55 | plugins: [ 56 | { 57 | name: 'anonymous:overrideConditions', 58 | config: c => { 59 | if (!c.resolve) { 60 | c.resolve = {} 61 | } 62 | if (!c.resolve.conditions) { 63 | c.resolve.conditions = [] 64 | } 65 | c.resolve.conditions = options?.customConditions ?? ['default'] 66 | } 67 | } 68 | ] 69 | }))) 70 | -------------------------------------------------------------------------------- /website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mono 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "type": "module", 4 | "version": "0.1.0", 5 | "author": { 6 | "name": "YiJie" 7 | }, 8 | "scripts": { 9 | "start": "vite" 10 | }, 11 | "imports": { 12 | "#~/*": "./src/*" 13 | }, 14 | "dependencies": { 15 | "@mono/utils": "workspace:*" 16 | }, 17 | "devDependencies": { 18 | "vite": "^5.4.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /website/src/index.share.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@mono/share' { 2 | export type Numbers = 123 | 456 3 | } 4 | -------------------------------------------------------------------------------- /website/src/index.ts: -------------------------------------------------------------------------------- 1 | import { foo } from '@mono/utils' 2 | import { bar } from '@mono/utils/bar' 3 | import { name } from '@mono/utils/readFile' 4 | // ^? 5 | import type { Numbers, Strings, User } from '@mono/share' 6 | 7 | import '#~/main.ts' 8 | 9 | // eslint-disable-next-line no-console 10 | console.log(name) 11 | // eslint-disable-next-line no-console 12 | console.log(foo(), bar()) 13 | 14 | const num: Numbers = 123 15 | // eslint-disable-next-line no-console 16 | console.log(num) 17 | const str: Strings = 'abc' 18 | // eslint-disable-next-line no-console 19 | console.log(str) 20 | 21 | const user: User = { 22 | name: 'foo' 23 | } 24 | // eslint-disable-next-line no-console 25 | console.log(user.name) 26 | -------------------------------------------------------------------------------- /website/src/main.ts: -------------------------------------------------------------------------------- 1 | document.querySelector('#app')!.innerHTML = 'Hello, World!' 2 | -------------------------------------------------------------------------------- /website/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | 3 | export default defineConfig({ 4 | resolve: { 5 | conditions: ['browser', 'module', 'import', 'default'] 6 | } 7 | }) 8 | --------------------------------------------------------------------------------