@fairgarden/monolith 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/Readme.md +84 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +160 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/compat.d.ts +4 -0
  7. package/dist/compat.d.ts.map +1 -0
  8. package/dist/compat.js +156 -0
  9. package/dist/compat.js.map +1 -0
  10. package/dist/eslint.d.ts +62 -0
  11. package/dist/eslint.d.ts.map +1 -0
  12. package/dist/eslint.js +198 -0
  13. package/dist/eslint.js.map +1 -0
  14. package/dist/index.d.ts +28 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +77 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/link.d.ts +24 -0
  19. package/dist/link.d.ts.map +1 -0
  20. package/dist/link.js +473 -0
  21. package/dist/link.js.map +1 -0
  22. package/dist/mounts.d.ts +37 -0
  23. package/dist/mounts.d.ts.map +1 -0
  24. package/dist/mounts.js +51 -0
  25. package/dist/mounts.js.map +1 -0
  26. package/dist/package-json.d.ts +38 -0
  27. package/dist/package-json.d.ts.map +1 -0
  28. package/dist/package-json.js +156 -0
  29. package/dist/package-json.js.map +1 -0
  30. package/dist/portability.d.ts +36 -0
  31. package/dist/portability.d.ts.map +1 -0
  32. package/dist/portability.js +158 -0
  33. package/dist/portability.js.map +1 -0
  34. package/dist/portable-link.d.ts +22 -0
  35. package/dist/portable-link.d.ts.map +1 -0
  36. package/dist/portable-link.js +24 -0
  37. package/dist/portable-link.js.map +1 -0
  38. package/dist/resolve.d.ts +5 -0
  39. package/dist/resolve.d.ts.map +1 -0
  40. package/dist/resolve.js +181 -0
  41. package/dist/resolve.js.map +1 -0
  42. package/dist/routes.d.ts +23 -0
  43. package/dist/routes.d.ts.map +1 -0
  44. package/dist/routes.js +95 -0
  45. package/dist/routes.js.map +1 -0
  46. package/dist/types.d.ts +111 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -0
  50. package/package.json +74 -0
package/dist/eslint.js ADDED
@@ -0,0 +1,198 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readFileSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ /** Directory names Next treats as a route tree. */
5
+ const ROUTE_DIRS = ['app', 'pages'];
6
+ const filenameOf = (context) => context.filename ?? context.getFilename?.() ?? '';
7
+ const packageRootCache = new Map();
8
+ /** Nearest directory above `from` holding a package.json. */
9
+ const packageRoot = (from) => {
10
+ const cached = packageRootCache.get(from);
11
+ if (cached !== undefined || packageRootCache.has(from))
12
+ return cached;
13
+ let current = from;
14
+ let found;
15
+ for (;;) {
16
+ if (existsSync(path.join(current, 'package.json'))) {
17
+ found = current;
18
+ break;
19
+ }
20
+ const parent = path.dirname(current);
21
+ if (parent === current)
22
+ break;
23
+ current = parent;
24
+ }
25
+ packageRootCache.set(from, found);
26
+ return found;
27
+ };
28
+ const packageNameOf = (root) => {
29
+ try {
30
+ const pkg = JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8'));
31
+ return typeof pkg.name === 'string' ? pkg.name : undefined;
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ };
37
+ /**
38
+ * The route tree this file belongs to, if any.
39
+ *
40
+ * Looks for `app/` or `pages/` directly under the package root, or under
41
+ * `src/`, which is where Next looks too.
42
+ */
43
+ const routeRootOf = (filename, root) => {
44
+ const relative = path.relative(root, filename);
45
+ if (relative.startsWith('..'))
46
+ return undefined;
47
+ const segments = relative.split(path.sep);
48
+ const [first, second] = segments;
49
+ if (ROUTE_DIRS.includes(first))
50
+ return path.join(root, first);
51
+ if (first === 'src' && ROUTE_DIRS.includes(second)) {
52
+ return path.join(root, 'src', second);
53
+ }
54
+ return undefined;
55
+ };
56
+ const isRelative = (request) => request === '.' || request === '..' || /^\.\.?\//.test(request);
57
+ const sourcesOf = (node) => {
58
+ if (node.source)
59
+ return [node.source];
60
+ // `import()` is an ImportExpression, whose argument list is `arguments`;
61
+ // `require()` is a CallExpression whose callee is the identifier.
62
+ if (node.type === 'ImportExpression' && node.arguments)
63
+ return node.arguments;
64
+ if (node.type === 'CallExpression' &&
65
+ node.callee?.type === 'Identifier' &&
66
+ node.callee.name === 'require' &&
67
+ node.arguments) {
68
+ return node.arguments;
69
+ }
70
+ return [];
71
+ };
72
+ const escapingImports = {
73
+ meta: {
74
+ type: 'problem',
75
+ docs: {
76
+ description: 'Disallow relative imports that reach outside a route tree, which do not survive being mounted in a monolith',
77
+ },
78
+ fixable: 'code',
79
+ schema: [
80
+ {
81
+ type: 'object',
82
+ properties: { packageName: { type: 'string' } },
83
+ additionalProperties: false,
84
+ },
85
+ ],
86
+ },
87
+ create(context) {
88
+ const filename = filenameOf(context);
89
+ const root = packageRoot(path.dirname(filename));
90
+ if (!root)
91
+ return {};
92
+ const routeRoot = routeRootOf(filename, root);
93
+ if (!routeRoot)
94
+ return {};
95
+ const option = (context.options[0] ?? {});
96
+ const packageName = option.packageName ?? packageNameOf(root);
97
+ const check = (node) => {
98
+ for (const source of sourcesOf(node)) {
99
+ const request = source.value;
100
+ if (typeof request !== 'string' || !isRelative(request))
101
+ continue;
102
+ const resolved = path.resolve(path.dirname(filename), request);
103
+ const inside = path.relative(routeRoot, resolved);
104
+ if (!inside.startsWith('..'))
105
+ continue;
106
+ const fromRoot = path.relative(root, resolved).split(path.sep).join('/');
107
+ // An import that climbs out of the package has no package-name form;
108
+ // offering one would fix working code into `@scope/name/../outside`.
109
+ const insidePackage = !fromRoot.startsWith('..');
110
+ const replacement = packageName && insidePackage ? `${packageName}/${fromRoot}` : undefined;
111
+ context.report({
112
+ node: source,
113
+ message: replacement
114
+ ? `Relative import reaches outside ${path.basename(routeRoot)}/ and breaks once this app is mounted. Use '${replacement}'.`
115
+ : `Relative import reaches outside ${path.basename(routeRoot)}/ and breaks once this app is mounted. Import it by package name.`,
116
+ ...(replacement && source.range
117
+ ? {
118
+ fix: (fixer) => fixer.replaceText(source, `'${replacement}'`),
119
+ }
120
+ : {}),
121
+ });
122
+ }
123
+ };
124
+ return {
125
+ ImportDeclaration: check,
126
+ ExportNamedDeclaration: check,
127
+ ExportAllDeclaration: check,
128
+ ImportExpression: check,
129
+ CallExpression: check,
130
+ };
131
+ },
132
+ };
133
+ const nextLink = {
134
+ meta: {
135
+ type: 'problem',
136
+ docs: {
137
+ description: 'Disallow next/link in route trees, whose hrefs are not prefixed when the app is mounted',
138
+ },
139
+ schema: [
140
+ {
141
+ type: 'object',
142
+ properties: { replacement: { type: 'string' } },
143
+ additionalProperties: false,
144
+ },
145
+ ],
146
+ },
147
+ create(context) {
148
+ const filename = filenameOf(context);
149
+ const root = packageRoot(path.dirname(filename));
150
+ if (!root || !routeRootOf(filename, root))
151
+ return {};
152
+ const option = (context.options[0] ?? {});
153
+ const check = (node) => {
154
+ for (const source of sourcesOf(node)) {
155
+ if (source.value !== 'next/link')
156
+ continue;
157
+ context.report({
158
+ node: source,
159
+ message: option.replacement
160
+ ? `next/link does not prefix hrefs with the app's mount point. Use '${option.replacement}'.`
161
+ : "next/link does not prefix hrefs with the app's mount point. Use a Link built with createLink() from '@fairgarden/monolith/link'.",
162
+ });
163
+ }
164
+ };
165
+ return { ImportDeclaration: check, ImportExpression: check };
166
+ },
167
+ };
168
+ export const rules = {
169
+ 'no-escaping-relative-imports': escapingImports,
170
+ 'no-next-link': nextLink,
171
+ };
172
+ /**
173
+ * ESLint plugin keeping an app's routes mountable.
174
+ *
175
+ * ```js
176
+ * // eslint.config.mjs
177
+ * import monolith from '@fairgarden/monolith/eslint'
178
+ *
179
+ * export default [...monolith.configs.recommended]
180
+ * ```
181
+ */
182
+ const plugin = {
183
+ meta: { name: '@fairgarden/monolith' },
184
+ rules,
185
+ configs: {},
186
+ };
187
+ plugin.configs.recommended = [
188
+ {
189
+ name: '@fairgarden/monolith/recommended',
190
+ plugins: { '@fairgarden/monolith': plugin },
191
+ rules: {
192
+ '@fairgarden/monolith/no-escaping-relative-imports': 'error',
193
+ '@fairgarden/monolith/no-next-link': 'warn',
194
+ },
195
+ },
196
+ ];
197
+ export default plugin;
198
+ //# sourceMappingURL=eslint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint.js","sourceRoot":"","sources":["../src/eslint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { NextConfig } from 'next';
2
+ import type { MonolithApps, MonolithOptions, ResolvedApp } from './types.ts';
3
+ export type { LinkStrategy, MonolithApp, MonolithApps, MonolithOptions, ResolvedApp, } from './types.ts';
4
+ export { prefixPath } from './routes.ts';
5
+ export { MOUNTS_ENV } from './mounts.ts';
6
+ export { withMonolithicPortability, findPortabilityProblems, type PortabilityOptions, } from './portability.ts';
7
+ export declare const getRegisteredApps: () => ResolvedApp[];
8
+ /**
9
+ * Compose several Next.js apps into one deployable app.
10
+ *
11
+ * Each app's routes are mounted at `/<name>` and its assets at
12
+ * `public/<name>`, and its rewrites, redirects and headers are merged into the
13
+ * monolith's with that same prefix.
14
+ *
15
+ * ```ts
16
+ * export default withMonolith(
17
+ * { reactStrictMode: true },
18
+ * { id: '@fairgarden/id', membership: '@fairgarden/membership' }
19
+ * )
20
+ * ```
21
+ *
22
+ * Apps may live in the surrounding monorepo or be plain dependencies. Because
23
+ * `basePath` is not used, links inside an app are not prefixed automatically —
24
+ * see the package README.
25
+ */
26
+ export declare const withMonolith: (nextConfig?: NextConfig, apps?: MonolithApps, options?: MonolithOptions) => ((phase: string) => Promise<NextConfig>);
27
+ export default withMonolith;
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AAMtC,OAAO,KAAK,EAEV,YAAY,EACZ,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,KAAK,kBAAkB,GACxB,MAAM,kBAAkB,CAAA;AAazB,eAAO,MAAM,iBAAiB,QAAO,WAAW,EAAgB,CAAA;AAehE;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,GACvB,aAAY,UAAe,EAC3B,OAAM,YAAiB,EACvB,UAAS,eAAoB,KAC5B,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAwCzC,CAAA;AAED,eAAe,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ import path from 'node:path';
2
+ import { assertCompatible } from "./compat.js";
3
+ import { linkApps } from "./link.js";
4
+ import { resolveApps } from "./resolve.js";
5
+ import { mergeHeaders, mergeRedirects, mergeRewrites } from "./routes.js";
6
+ import { MOUNTS_ENV } from "./mounts.js";
7
+ export { prefixPath } from "./routes.js";
8
+ export { MOUNTS_ENV } from "./mounts.js";
9
+ export { withMonolithicPortability, findPortabilityProblems, } from "./portability.js";
10
+ const PHASE_DEVELOPMENT_SERVER = 'phase-development-server';
11
+ /**
12
+ * Set by the CLI, which loads the monolith's config only to discover which apps
13
+ * it composes and must not touch the file tree while doing so.
14
+ */
15
+ const skipLinking = () => process.env.FG_MONOLITH_SKIP_LINK === '1';
16
+ /** Apps seen by the most recent `withMonolith` evaluation, for the CLI. */
17
+ let registered = [];
18
+ export const getRegisteredApps = () => registered;
19
+ /**
20
+ * `next build` follows the committed symlinks, so it reads the source tree as
21
+ * it stands. `next dev` does not discover routes through a symlinked
22
+ * directory, so it gets a derived tree with the files symlinked individually.
23
+ */
24
+ const pickStrategy = (strategy, phase) => {
25
+ if (strategy && strategy !== 'auto')
26
+ return strategy;
27
+ return phase === PHASE_DEVELOPMENT_SERVER ? 'mirror' : 'source';
28
+ };
29
+ /**
30
+ * Compose several Next.js apps into one deployable app.
31
+ *
32
+ * Each app's routes are mounted at `/<name>` and its assets at
33
+ * `public/<name>`, and its rewrites, redirects and headers are merged into the
34
+ * monolith's with that same prefix.
35
+ *
36
+ * ```ts
37
+ * export default withMonolith(
38
+ * { reactStrictMode: true },
39
+ * { id: '@fairgarden/id', membership: '@fairgarden/membership' }
40
+ * )
41
+ * ```
42
+ *
43
+ * Apps may live in the surrounding monorepo or be plain dependencies. Because
44
+ * `basePath` is not used, links inside an app are not prefixed automatically —
45
+ * see the package README.
46
+ */
47
+ export const withMonolith = (nextConfig = {}, apps = {}, options = {}) => {
48
+ return async (phase) => {
49
+ const root = options.root ?? process.cwd();
50
+ const resolved = await resolveApps(root, apps, phase);
51
+ assertCompatible(nextConfig, resolved, root);
52
+ registered = resolved;
53
+ if (!skipLinking()) {
54
+ const strategy = pickStrategy(options.strategy, phase);
55
+ const sourceDir = path.resolve(root, options.sourceDir ?? path.join('src', 'app'));
56
+ await linkApps(root, resolved, {
57
+ strategy,
58
+ sourceDir,
59
+ sourcePagesDir: path.join(path.dirname(sourceDir), 'pages'),
60
+ selfReference: options.selfReference,
61
+ // Only needed to notice routes being added or removed.
62
+ watch: options.watch ??
63
+ (strategy !== 'source' && phase === PHASE_DEVELOPMENT_SERVER),
64
+ });
65
+ }
66
+ const mounts = Object.fromEntries(resolved.flatMap((app) => app.packageName ? [[app.packageName, app.prefix]] : []));
67
+ return {
68
+ ...nextConfig,
69
+ env: { ...nextConfig.env, [MOUNTS_ENV]: JSON.stringify(mounts) },
70
+ rewrites: await mergeRewrites(nextConfig, resolved),
71
+ redirects: await mergeRedirects(nextConfig, resolved),
72
+ headers: await mergeHeaders(nextConfig, resolved),
73
+ };
74
+ };
75
+ };
76
+ export default withMonolith;
77
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/link.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { LinkStrategy, ResolvedApp } from './types.ts';
2
+ export interface LinkOptions {
3
+ strategy: LinkStrategy;
4
+ watch: boolean;
5
+ /** Committed App Router directory, absolute. */
6
+ sourceDir: string;
7
+ /** Committed Pages Router directory, absolute. */
8
+ sourcePagesDir: string;
9
+ selfReference?: boolean;
10
+ }
11
+ /**
12
+ * Make an app resolvable by its own package name from inside its own tree.
13
+ *
14
+ * Apps import their own modules by package name, because relative imports stop
15
+ * working once the routes are mounted elsewhere. Turbopack resolves a mounted
16
+ * file from its real location, so the monolith's `node_modules` is not on the
17
+ * lookup path and the app has to be able to find itself.
18
+ *
19
+ * Leaves a real installed package alone, and only replaces a symlink it would
20
+ * have created itself.
21
+ */
22
+ export declare const linkSelfReference: (app: ResolvedApp) => Promise<void>;
23
+ export declare const linkApps: (monolithRoot: string, apps: ResolvedApp[], options: LinkOptions) => Promise<string[]>;
24
+ //# sourceMappingURL=link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../src/link.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE3D,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,YAAY,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;IACd,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAA;IACjB,kDAAkD;IAClD,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAmND;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAAU,KAAK,WAAW,KAAG,OAAO,CAAC,IAAI,CActE,CAAA;AAwND,eAAO,MAAM,QAAQ,GACnB,cAAc,MAAM,EACpB,MAAM,WAAW,EAAE,EACnB,SAAS,WAAW,KACnB,OAAO,CAAC,MAAM,EAAE,CAiJlB,CAAA"}