From 4121fc926ea3e4aa4f66ed337fa2ad10eaa7d00c Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sat, 28 Jan 2023 17:59:59 +0100 Subject: [PATCH] write more about packages / monorepo setup --- website/src/config.ts | 1 + .../src/pages/technical-manual/packages.mdx | 73 ++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/website/src/config.ts b/website/src/config.ts index db724a5b..f7f46268 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -76,6 +76,7 @@ export const SIDEBAR: Sidebar = { { text: 'REPL', link: 'technical-manual/repl' }, { text: 'Docs', link: 'technical-manual/docs' }, { text: 'Testing', link: 'technical-manual/testing' }, + { text: 'Packages', link: 'technical-manual/packages' }, // { text: 'Internals', link: 'technical-manual/internals' }, ], }, diff --git a/website/src/pages/technical-manual/packages.mdx b/website/src/pages/technical-manual/packages.mdx index b4beeda6..4f198af8 100644 --- a/website/src/pages/technical-manual/packages.mdx +++ b/website/src/pages/technical-manual/packages.mdx @@ -1,10 +1,79 @@ +--- +title: Strudel Packages +layout: ../../layouts/MainLayout.astro +--- + +import { MiniRepl } from '../../docs/MiniRepl'; + ## Strudel Packages +The [strudel repo](github.com/tidalcycles/strudel) is organized into packages, using [npm workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces). +Publishing packages is done with [lerna](https://lerna.js.org/). + There are different packages for different purposes. They.. - split up the code into smaller chunks - can be selectively used to implement some sort of time based system -Please refer to the individual README files in the [packages folder](https://github.com/tidalcycles/strudel/tree/main/packages) +[See the latest published packages on npm](https://www.npmjs.com/search?q=%40strudel.cycles). -TODO +### Important bits + +- The [root package.json](https://github.com/tidalcycles/strudel/blob/main/package.json) specifies `packages/*` as `workspaces` +- Each folder in `packages` comes with its own `package.json`, defining a package name of the format `@strudel.cycles/` +- Running `npm i` from the root folder will symlink all packages to the `node_modules` folder, e.g. `node_modules/@strudel.cycles/core` symlinks `packages/core` +- These symlinks allow importing the packages with their package name, instead of a relative path, e.g. `import { seq } from '@strudel.cycles/core'`, instead of `import { seq } from '../core/`. + This works because the [bare module import](https://vitejs.dev/guide/features.html#npm-dependency-resolving-and-pre-bundling) `@strudel.cycles/core` is resolved to `node_modules/@strudel.cycles/core`. + In a project that installs the published packages from npm, these imports will still work, whereas relative ones might not. +- When a strudel package is importing from another strudel package, the package that is imported from should be listed in the `dependencies` field of the `package.json`. + For example, [@strudel.cycles/mini lists `@strudel.cycles/core` as a dependency](https://github.com/tidalcycles/strudel/blob/main/packages/mini/package.json). +- In development, files in any package can be changed and saved to instantly update the dev server via [hot module replacement](https://vitejs.dev/guide/features.html#hot-module-replacement) +- To publish packages, `npx lerna publish` will check which packages were changed since the last publish and publish only those. + The version numbers in the dependencies of each packages will be updated automatically to the latest version. + +### Building & Publishing + +Currently, all packages are only published as ESM with vite flavour. +To build standardized ESM and CJS files, a `vite.config.js` like that is needed: + +```js +import { defineConfig } from 'vite'; +import { dependencies } from './package.json'; +import { resolve } from 'path'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [], + build: { + lib: { + entry: resolve(__dirname, 'index.mjs'), + formats: ['es', 'cjs'], + fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' }[ext]), + }, + rollupOptions: { + external: [...Object.keys(dependencies)], + }, + target: 'esnext', + }, +}); +``` + +This will build `index.mjs` (ESM) and `index.js` (CJS) to the dist folder. + +### What's the main file? + +Currently, each package uses the unbundled `index.mjs` as its main file, which must change for the published version. +There are 2 ways to handle this: + +1. `main` = `dist/index.js`, `module` = `dist/index.mjs`. The built files are used. This means that changing a source file won't take effect in the dev server without a rebuild. +2. Use different `package.json` files for dev vs publish. So the unbuilt `index.mjs` could be used in dev, while the built files can be used when publishing. + +Option 1 could be done with [workspace watching](https://lerna.js.org/docs/features/workspace-watching), although it might make the dev server less snappy.. +Option 2 can be done by [publishing just the dist folder and copying over the `package.json` file](https://stackoverflow.com/questions/37862712/how-to-publish-contents-only-of-a-specific-folder). +Sadly, [this does not fit into how lerna works](https://github.com/lerna/lerna/issues/91). + +https://github.com/changesets/changesets + +https://turbo.build/repo/docs/handbook/publishing-packages/versioning-and-publishing + +https://pnpm.io/workspaces \ No newline at end of file