TypeScript/ECMA
mono-dev packages itself as a node module. In TypeScript/ECMAScript
projects, the package needs to be declared in package.json to be
managed by the package manager. For example
{
"devDependencies": {
"mono-dev": "workspace:*"
}
}
The build scripts can be included in Taskfile.yml
version: '3'
includes:
ecma:
taskfile: ./node_modules/mono-dev/task/ecma.yaml
internal: true
Check and Fix
mono-dev ships with its own “zero config” linter mono-lint that wraps
tsc, eslint and prettier with pre-defined rules.
tasks:
check:
cmds:
- task: ecma:mono-check
fix:
cmds:
- task: ecma:mono-fix
It scans the project and generates config files on the fly.
However, for other tools like tsserver to work properly, these config files need to be in the project
rather than hidden away in some place already ignored by VCS.
So, you have to add these entries to your .gitignore:
.prettierignore
/tsconfig*.json
/eslint.config.js
This is behavior of mono-lint:
- TypeScript projects are directory-based. Each directory is type-checked separately
and allow for different env config (for example,
srcvsscripts) - no DOM and no types exist by default. They need to be manually included in
env.d.tsin each directory. Only directories withenv.d.tswill be checked. - If root directory contain any TypeScript stuff, it will be checked as well
- ESLint only checks the TypeScript projects. If you use ECMAScript, you opt-out of safety anyway
For code that should be involved with type-checking, but ignored for other checks (usually generated code),
a "nocheck" array in top-level of package.json can be provided using the same syntax as .gitignore,
for example:
{
"devDependencies": {
"mono-dev": "workspace:*"
},
"nocheck": ["/src/generated"]
}
Paths in nocheck will not be processed by eslint or prettier
Remapping TS Import Path
TS import paths can be remapped in bundled apps to avoid the “relative parent import hell”.
mono-lint automatically detects suitable scenarios to generate these import maps using a self::
prefix.
The conditions for import map to be generated are:
-
package.jsonmust NOT contain"name","file"or"exports"key, AND there is nosrc/index.(c|m)?tsx?file. These suggest the package is a library instead of bundled app -
The import paths can only be generated for the
srcdirectory -
One import path for the first
index.(c|m)?tsx?found for each directory insrc.
For max interop with tools such as bun, the same import map
will appear in tsconfig.json and tsconfig.src.json.
Test
To add testing support, add vitest to the downstream project as devdependencies
pnpm i -D vitest
vitest supports zero config out-of-the-box, see documentation for more.
Use ecma:vitest and ecma:vitest-watch tasks for running the test once or in watch mode.
Vite
mono-dev ships a baseline vite config that adds common plugins
and configs to my projects.
Add vite to the downstream project, with vite.config.ts at the root:
import { defineConfig } from "vite";
import monodev from "mono-dev/vite";
// see type definition for more info
const monodevConfig = monodev({
https: true, // if secure context is needed, needs trusted certificate
wasm: true, // if wasm
worker: "es", // if ES worker is needed
});
// wrap vite config with monodevConfig
export default defineConfig(monodevConfig({
/** normal vite config here */
});
These plugins are automatically added:
- react
- yaml
- typescript paths
Define vite types in src/env.d.ts:
/// <reference types="vite/client" />
/// <reference types="mono-dev/vite/client" />
/// <reference types="dom" />
/// <reference types="dom.iterable" />
Use the ecma:vite-dev and ecma:vite-build tasks to execute vite
dev server and build.