chore: setup pnpm workspace monorepo structure

- Add pnpm-workspace.yaml for monorepo configuration
- Move esbuild-plugin-inline-worker to workspace package
- Update package.json to use workspace:* references
- Add workspace-related entries to .gitignore
This commit is contained in:
Quorafind 2025-11-26 10:28:57 +08:00
parent 8ffd5cee0e
commit 06f0e89638
12 changed files with 3205 additions and 954 deletions

7
.gitignore vendored
View file

@ -44,5 +44,12 @@ CLAUDE.md
dist
dist/*
# Workspace packages build artifacts
packages/*/dist
packages/*/node_modules
# Keep calendar package .git for independent management
!packages/calendar/.git
# Documentation site (separate repository)
docs-site

View file

@ -55,7 +55,7 @@
"cross-env": "^7.0.3",
"dotenv": "^17.2.1",
"esbuild": "0.25.9",
"esbuild-plugin-inline-worker": "https://github.com/mitschabaude/esbuild-plugin-inline-worker",
"esbuild-plugin-inline-worker": "workspace:*",
"globby": "^14.1.0",
"husky": "^9.1.7",
"jest": "^29.5.0",
@ -65,19 +65,20 @@
"release-it": "^19.0.4",
"semver": "^7.7.2",
"ts-jest": "^29.1.0",
"typescript": "4.7.3",
"tslib": "2.4.0"
"tslib": "2.4.0",
"typescript": "4.7.3"
},
"dependencies": {
"@popperjs/core": "^2.11.8",
"@taskgenius/calendar": "workspace:*",
"@types/sortablejs": "^1.15.8",
"chrono-node": "^2.7.6",
"date-fns": "^4.1.0",
"localforage": "^1.10.0",
"rrule": "^2.8.1",
"obsidian": "^1.10.0",
"obsidian-daily-notes-interface": "^0.9.4",
"sortablejs": "^1.15.6",
"regexp-match-indices": "^1.0.2"
"regexp-match-indices": "^1.0.2",
"rrule": "^2.8.1",
"sortablejs": "^1.15.6"
}
}

View file

@ -0,0 +1,16 @@
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
"no-unused-vars": "warn",
"no-empty": "off"
}
}

View file

@ -0,0 +1,3 @@
node_modules
.vscode
dist

View file

@ -0,0 +1,7 @@
Copyright 2021 Gregor Mitscha-Baude
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,77 @@
# esbuild-plugin-inline-worker
This is a plugin for [esbuild](https://esbuild.github.io) which allows you to import `.worker.js` files to get the constructor for a Web Worker, similar to [worker-loader](https://github.com/webpack-contrib/worker-loader) for Webpack.
```sh
yarn add esbuild-plugin-inline-worker
```
Example:
```js
// example.worker.js
postMessage('hello from worker!');
```
```js
// example.js
import Worker from './example.worker.js';
let worker = Worker();
worker.onmessage = ({data}) => console.log(data);
```
In this example, `worker` will be an instance of [Worker](https://developer.mozilla.org/en-US/docs/Web/API/Worker).
Conveniently, you don't have to take care of having the worker's JavaScript file in the right location on your server. Instead, the JS code for the worker is inlined to the bundle produced by esbuild. This makes this plugin perfect for JS library authors who want to use workers for performance optimization, where the need for a separate worker file is awkward.
The inlined worker code will be created with a separate call to esbuild. That means your worker code can import libraries and use TypeScript or JSX!
Supported file extensions for the worker are `.worker.js`, `.worker.ts`, `.worker.jsx`, `.worker.tsx`.
## Usage
```js
import {build} from 'esbuild';
import inlineWorkerPlugin from 'esbuild-plugin-inline-worker';
build({
/* ... */
plugins: [inlineWorkerPlugin()],
});
```
## Build configuration
Optionally, you can pass a configuration object which has the same interface as esbuild's [build API](https://esbuild.github.io/api/#build-api), which determines how the worker code is bundled:
```ts
export type InlineWorkerPluginConfig = {
buildOptions?: BuildOptions;
workerName?: string
workerArguments?: WorkerOptions
}
```
```js
inlineWorkerPlugin(workerPluginConfig);
```
This is how your custom config is used internally:
```js
if (pluginConfig.buildOptions) {
delete pluginConfig.buildOptions.entryPoints;
delete pluginConfig.buildOptions.outfile;
delete pluginConfig.buildOptions.outdir;
}
await build({
entryPoints: [workerPath],
bundle: true,
minify: true,
outfile: bundlePath,
target: "es2017",
format: "esm",
...pluginConfig.buildOptions,
});
```

View file

@ -0,0 +1,103 @@
import { type BuildOptions, type PluginBuild, build } from "esbuild";
import findCacheDir from "find-cache-dir";
import fs from "fs";
import path from "path";
export type InlineWorkerPluginConfig = {
buildOptions?: BuildOptions;
workerName?: string;
workerArguments?: WorkerOptions;
};
export default function inlineWorkerPlugin(
workerPluginConfig: InlineWorkerPluginConfig = {}
) {
return {
name: "esbuild-plugin-inline-worker",
setup(build: PluginBuild) {
build.onLoad(
{ filter: /\.worker.(js|jsx|ts|tsx)$/ },
async ({ path: workerPath }) => {
// const workerCode = await fs.promises.readFile(workerPath, {
// encoding: 'utf-8',
// });
const workerCode = await buildWorker(
workerPath,
workerPluginConfig
);
return {
contents: `import inlineWorker from '__inline-worker'
export default function Worker() {
return inlineWorker(${JSON.stringify(workerCode)});
}
`,
loader: "js",
};
}
);
const options: WorkerOptions = {
name: workerPluginConfig.workerName || undefined,
...workerPluginConfig.workerArguments,
};
const inlineWorkerFunctionCode = `
export default function inlineWorker(scriptText) {
const blob = new Blob([scriptText], {type: 'text/javascript'});
const url = URL.createObjectURL(blob);
const worker = new Worker(url, ${JSON.stringify(options)});
URL.revokeObjectURL(url);
return worker;
}
`;
build.onResolve({ filter: /^__inline-worker$/ }, ({ path }) => {
return { path, namespace: "inline-worker" };
});
build.onLoad({ filter: /.*/, namespace: "inline-worker" }, () => {
return { contents: inlineWorkerFunctionCode, loader: "js" };
});
},
};
}
const cacheDir = findCacheDir({
name: "esbuild-plugin-inline-worker",
create: true,
});
async function buildWorker(
workerPath: string,
pluginConfig: InlineWorkerPluginConfig
) {
const scriptNameParts = path.basename(workerPath).split(".");
scriptNameParts.pop();
scriptNameParts.push("js");
const scriptName = scriptNameParts.join(".");
if (!cacheDir) {
throw new Error(
"Cache directory not found. Please ensure 'find-cache-dir' is installed."
);
}
const bundlePath = path.resolve(cacheDir, scriptName);
if (pluginConfig.buildOptions) {
delete pluginConfig.buildOptions.entryPoints;
delete pluginConfig.buildOptions.outfile;
delete pluginConfig.buildOptions.outdir;
}
await build({
entryPoints: [workerPath],
bundle: true,
minify: true,
outfile: bundlePath,
target: "es2017",
format: "esm",
...pluginConfig.buildOptions,
});
return fs.promises.readFile(bundlePath, { encoding: "utf-8" });
}

View file

@ -0,0 +1,43 @@
{
"name": "esbuild-plugin-inline-worker",
"description": "Esbuild loader for inline Web Workers",
"version": "0.1.1",
"repository": {
"type": "git",
"url": "https://github.com/mitschabaude/esbuild-plugin-inline-worker"
},
"keywords": [
"workers",
"esbuild"
],
"author": "Gregor <gregor.mitscha-baude@gmx.at>",
"license": "MIT",
"type": "module",
"main": "dist/index.js",
"exports": {
".": {
"import": "./dist/index.js"
}
},
"browser": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist/"
],
"scripts": {
"build": "tsc",
"clean": "rm -rf dist",
"prepare": "npm run build",
"prepublishOnly": "npm run clean && npm run build"
},
"dependencies": {
"find-cache-dir": "^3.3.1"
},
"peerDependencies": {
"esbuild": ">=0.14.0"
},
"devDependencies": {
"@types/node": "^24.2.0",
"typescript": "^5.9.2"
}
}

View file

@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2017",
"module": "ESNext",
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./",
"allowJs": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"types": ["node"],
"typeRoots": [
"./types",
"./node_modules/@types"
]
},
"include": [
"index.ts",
"types/**/*"
],
"exclude": [
"node_modules",
"dist"
]
}

View file

@ -0,0 +1,24 @@
declare module 'find-cache-dir' {
interface Options {
/** Name of the cache directory. */
name: string;
/** Create the cache directory if it doesn't exist. */
create?: boolean;
/** Current working directory to start searching from. */
cwd?: string;
/** Cache directory to look for. */
files?: string[];
/** Stop looking for cache directory after this directory. */
thunk?: boolean;
}
/**
* Finds the cache directory for a given name.
* @param options - Configuration options
* @returns The path to the cache directory or null if not found
*/
function findCacheDir(options: Options): string | null;
function findCacheDir(options: Options & { create: true }): string;
export = findCacheDir;
}

File diff suppressed because it is too large Load diff

5
pnpm-workspace.yaml Normal file
View file

@ -0,0 +1,5 @@
packages:
- "packages/*"
onlyBuiltDependencies:
- esbuild