@quilted/rollup 0.2.4 → 0.2.5

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.
@@ -2,15 +2,13 @@ import * as path from 'node:path';
2
2
  import * as fs from 'node:fs/promises';
3
3
  import { exec as exec$1 } from 'node:child_process';
4
4
  import { promisify } from 'node:util';
5
- import { glob } from 'glob';
6
5
  import { multiline } from './shared/strings.mjs';
7
- import { resolveRoot } from './shared/path.mjs';
6
+ import { Project, sourceEntriesForProject } from './shared/project.mjs';
8
7
  import { getNodePlugins, removeBuildFiles } from './shared/rollup.mjs';
9
- import { loadPackageJSON } from './shared/package-json.mjs';
10
8
  import { getBrowserGroupTargetDetails, rollupGenerateOptionsForBrowsers } from './shared/browserslist.mjs';
11
9
 
12
10
  async function quiltPackage({
13
- root: rootPath = process.cwd(),
11
+ root = process.cwd(),
14
12
  commonjs = false,
15
13
  esnext: explicitESNext,
16
14
  entries,
@@ -20,9 +18,8 @@ async function quiltPackage({
20
18
  graphql = true,
21
19
  customize
22
20
  } = {}) {
23
- const root = resolveRoot(rootPath);
24
- const packageJSON = await loadPackageJSON(root);
25
- const resolvedEntries = entries ?? await sourceEntriesForPackage(root, packageJSON);
21
+ const project = Project.load(root);
22
+ const resolvedEntries = entries ?? await sourceEntriesForProject(project);
26
23
  const includeESNext = explicitESNext ?? Object.keys(resolvedEntries).length > 0;
27
24
  const [esm, esnext] = await Promise.all([
28
25
  quiltPackageESModules({
@@ -47,31 +44,34 @@ async function quiltPackage({
47
44
  return esnext ? [esm, esnext] : [esm];
48
45
  }
49
46
  async function quiltPackageESModules({
50
- root: rootPath = process.cwd(),
47
+ root = process.cwd(),
51
48
  commonjs = false,
52
49
  entries,
53
50
  executable = {},
54
- react,
51
+ react: useReact,
55
52
  bundle,
56
53
  graphql = true,
57
54
  customize
58
55
  } = {}) {
59
- const root = resolveRoot(rootPath);
60
- const outputDirectory = path.resolve(root, "build/esm");
56
+ const project = Project.load(root);
57
+ const outputDirectory = project.resolve("build/esm");
61
58
  const hasExecutables = Object.keys(executable).length > 0;
62
- const [{ sourceCode }, { esnext }, nodePlugins, packageJSON, browserGroup] = await Promise.all([
59
+ const [{ sourceCode }, { react }, { esnext }, nodePlugins, browserGroup] = await Promise.all([
63
60
  import('./features/source-code.mjs'),
61
+ import('./features/react.mjs'),
64
62
  import('./features/esnext.mjs'),
65
63
  getNodePlugins({ bundle }),
66
- loadPackageJSON(root),
67
- getBrowserGroupTargetDetails({ name: "default" }, { root })
64
+ getBrowserGroupTargetDetails({ name: "default" }, { root: project.root })
68
65
  ]);
69
- const resolvedEntries = entries ?? await sourceEntriesForPackage(root, packageJSON);
66
+ const resolvedEntries = entries ?? await sourceEntriesForProject(project);
70
67
  const hasEntries = Object.keys(resolvedEntries).length > 0;
71
- const source = sourceForEntries({ ...resolvedEntries, ...executable }, { root });
68
+ const source = sourceForEntries(
69
+ { ...resolvedEntries, ...executable },
70
+ { root: project.root }
71
+ );
72
72
  const plugins = [
73
73
  ...nodePlugins,
74
- sourceCode({ mode: "production", react }),
74
+ sourceCode({ mode: "production", react: useReact }),
75
75
  esnext({ mode: "production", babel: false }),
76
76
  removeBuildFiles(
77
77
  [
@@ -79,11 +79,14 @@ async function quiltPackageESModules({
79
79
  ...commonjs ? ["build/cjs"] : [],
80
80
  ...hasExecutables ? ["bin"] : []
81
81
  ],
82
- { root }
82
+ { root: project.root }
83
83
  )
84
84
  ];
85
+ if (useReact) {
86
+ plugins.push(react());
87
+ }
85
88
  if (hasExecutables) {
86
- plugins.push(packageExecutables(executable, { root }));
89
+ plugins.push(packageExecutables(executable, { root: project.root }));
87
90
  }
88
91
  if (graphql) {
89
92
  const { graphql: graphql2 } = await import('./features/graphql.mjs');
@@ -121,12 +124,6 @@ async function quiltPackageESModules({
121
124
  const options = {
122
125
  input: source.files,
123
126
  plugins,
124
- onwarn(warning, defaultWarn) {
125
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && /['"]use client['"]/.test(warning.message)) {
126
- return;
127
- }
128
- defaultWarn(warning);
129
- },
130
127
  output
131
128
  };
132
129
  if (customize) {
@@ -148,29 +145,32 @@ async function quiltPackageESModules({
148
145
  }
149
146
  }
150
147
  async function quiltPackageESNext({
151
- root: rootPath = process.cwd(),
152
- react,
148
+ root = process.cwd(),
149
+ react: useReact,
153
150
  graphql = true,
154
151
  entries,
155
152
  bundle,
156
153
  customize
157
154
  } = {}) {
158
- const root = resolveRoot(rootPath);
159
- const outputDirectory = path.join(root, "build/esnext");
160
- const [{ sourceCode }, { esnext }, nodePlugins, packageJSON] = await Promise.all([
155
+ const project = Project.load(root);
156
+ const outputDirectory = project.resolve("build/esnext");
157
+ const [{ sourceCode }, { react }, { esnext }, nodePlugins] = await Promise.all([
161
158
  import('./features/source-code.mjs'),
159
+ import('./features/react.mjs'),
162
160
  import('./features/esnext.mjs'),
163
- getNodePlugins({ bundle }),
164
- loadPackageJSON(root)
161
+ getNodePlugins({ bundle })
165
162
  ]);
166
- const resolvedEntries = entries ?? await sourceEntriesForPackage(root, packageJSON);
167
- const source = sourceForEntries(resolvedEntries, { root });
163
+ const resolvedEntries = entries ?? await sourceEntriesForProject(project);
164
+ const source = sourceForEntries(resolvedEntries, { root: project.root });
168
165
  const plugins = [
169
166
  ...nodePlugins,
170
- sourceCode({ mode: "production", babel: false, react }),
167
+ sourceCode({ mode: "production", babel: false, react: useReact }),
171
168
  esnext({ mode: "production", babel: false }),
172
- removeBuildFiles(["build/esnext"], { root })
169
+ removeBuildFiles(["build/esnext"], { root: project.root })
173
170
  ];
171
+ if (useReact) {
172
+ plugins.push(react());
173
+ }
174
174
  if (graphql) {
175
175
  const { graphql: graphql2 } = await import('./features/graphql.mjs');
176
176
  plugins.push(graphql2({ manifest: false }));
@@ -292,48 +292,5 @@ function sourceForEntries(entries, { root }) {
292
292
  }
293
293
  return { root: sourceRoot, files: sourceEntryFiles };
294
294
  }
295
- async function sourceEntriesForPackage(root, packageJSON) {
296
- const { main, exports } = packageJSON;
297
- const entries = {};
298
- if (typeof main === "string") {
299
- entries["."] = await resolveTargetFileAsSource(main, root);
300
- }
301
- if (typeof exports === "string") {
302
- entries["."] = await resolveTargetFileAsSource(exports, root);
303
- return entries;
304
- } else if (exports == null || typeof exports !== "object") {
305
- return entries;
306
- }
307
- for (const [exportPath, exportCondition] of Object.entries(
308
- exports
309
- )) {
310
- let targetFile = null;
311
- if (exportCondition == null)
312
- continue;
313
- if (typeof exportCondition === "string") {
314
- targetFile = exportCondition;
315
- } else {
316
- targetFile ??= exportCondition["source"] ?? exportCondition["quilt:source"] ?? exportCondition["quilt:esnext"] ?? Object.values(exportCondition).find(
317
- (condition) => typeof condition === "string" && condition.startsWith("./build/")
318
- );
319
- }
320
- if (targetFile == null)
321
- continue;
322
- const sourceFile = await resolveTargetFileAsSource(targetFile, root);
323
- entries[exportPath] = sourceFile;
324
- }
325
- return entries;
326
- }
327
- async function resolveTargetFileAsSource(file, root) {
328
- const sourceFile = file.includes("/build/") ? (await glob(
329
- file.replace(/[/]build[/][^/]+[/]/, "/*/").replace(/(\.d\.ts|\.[\w]+)$/, ".*"),
330
- {
331
- cwd: root,
332
- absolute: true,
333
- ignore: [path.resolve(root, file)]
334
- }
335
- ))[0] : path.resolve(root, file);
336
- return sourceFile;
337
- }
338
295
 
339
296
  export { packageExecutables, quiltPackage, quiltPackageESModules, quiltPackageESNext };
@@ -1,8 +1,5 @@
1
- import * as path from 'node:path';
2
- import { glob } from 'glob';
1
+ import { Project } from './shared/project.mjs';
3
2
  import { getNodePlugins, removeBuildFiles } from './shared/rollup.mjs';
4
- import { resolveRoot } from './shared/path.mjs';
5
- import { loadPackageJSON } from './shared/package-json.mjs';
6
3
  import { magicModuleRequestRouterEntry } from './features/request-router.mjs';
7
4
  import { resolveEnvOption } from './features/env.mjs';
8
5
  import { MAGIC_MODULE_ENTRY, MAGIC_MODULE_REQUEST_ROUTER } from './constants.mjs';
@@ -18,9 +15,9 @@ async function quiltServer({
18
15
  port,
19
16
  host
20
17
  } = {}) {
21
- const root = resolveRoot(rootPath);
18
+ const project = Project.load(rootPath);
22
19
  const mode = (typeof env === "object" ? env?.mode : void 0) ?? "production";
23
- const outputDirectory = path.join(root, "build/server");
20
+ const outputDirectory = project.resolve("build/server");
24
21
  const minify = output?.minify ?? false;
25
22
  const bundle = output?.bundle;
26
23
  const hash = output?.hash ?? "async-only";
@@ -30,31 +27,32 @@ async function quiltServer({
30
27
  { magicModuleEnv, replaceProcessEnv },
31
28
  { sourceCode },
32
29
  { tsconfigAliases },
30
+ { monorepoPackageAliases },
33
31
  { react },
34
32
  { esnext },
35
- nodePlugins,
36
- packageJSON
33
+ nodePlugins
37
34
  ] = await Promise.all([
38
35
  import('rollup-plugin-visualizer'),
39
36
  import('./features/env.mjs'),
40
37
  import('./features/source-code.mjs'),
41
38
  import('./features/typescript.mjs'),
39
+ import('./features/node.mjs'),
42
40
  import('./features/react.mjs'),
43
41
  import('./features/esnext.mjs'),
44
- getNodePlugins({ bundle }),
45
- loadPackageJSON(root)
42
+ getNodePlugins({ bundle })
46
43
  ]);
47
- const serverEntry = entry ? path.resolve(root, entry) : await sourceForServer(root, packageJSON);
44
+ const serverEntry = entry ? project.resolve(entry) : await sourceForServer(project);
48
45
  const finalEntry = format === "request-router" ? MAGIC_MODULE_ENTRY : serverEntry ?? MAGIC_MODULE_ENTRY;
49
46
  const plugins = [
50
47
  ...nodePlugins,
51
48
  replaceProcessEnv({ mode }),
52
49
  magicModuleEnv({ ...resolveEnvOption(env), mode }),
53
50
  sourceCode({ mode, targets: ["current node"] }),
54
- tsconfigAliases({ root }),
51
+ tsconfigAliases({ root: project.root }),
52
+ monorepoPackageAliases({ root: project.root }),
55
53
  react(),
56
54
  esnext({ mode, targets: ["current node"] }),
57
- removeBuildFiles(["build/server", "build/reports"], { root })
55
+ removeBuildFiles(["build/server", "build/reports"], { root: project.root })
58
56
  ];
59
57
  if (format === "request-router") {
60
58
  plugins.push(
@@ -82,18 +80,12 @@ async function quiltServer({
82
80
  template: "treemap",
83
81
  open: false,
84
82
  brotliSize: true,
85
- filename: path.resolve(root, `build/reports/bundle-visualizer.html`)
83
+ filename: project.resolve(`build/reports/bundle-visualizer.html`)
86
84
  })
87
85
  );
88
86
  return {
89
87
  input: finalEntry === MAGIC_MODULE_ENTRY ? { server: finalEntry } : finalEntry,
90
88
  plugins,
91
- onwarn(warning, defaultWarn) {
92
- if (warning.code === "MODULE_LEVEL_DIRECTIVE" && /['"]use client['"]/.test(warning.message)) {
93
- return;
94
- }
95
- defaultWarn(warning);
96
- },
97
89
  output: {
98
90
  format: outputFormat === "commonjs" || outputFormat === "cjs" ? "cjs" : "esm",
99
91
  dir: outputDirectory,
@@ -104,16 +96,15 @@ async function quiltServer({
104
96
  }
105
97
  };
106
98
  }
107
- async function sourceForServer(root, packageJSON) {
108
- const { main, exports } = packageJSON;
99
+ async function sourceForServer(project) {
100
+ const { main, exports } = project.packageJSON.raw;
109
101
  const entryFromPackageJSON = main ?? exports?.["."];
110
102
  if (entryFromPackageJSON) {
111
- return path.resolve(root, entryFromPackageJSON);
103
+ return project.resolve(entryFromPackageJSON);
112
104
  }
113
- const possibleSourceFiles = await glob(
105
+ const possibleSourceFiles = await project.glob(
114
106
  "{index,server,service,backend,entry,input}.{ts,tsx,mjs,js,jsx}",
115
107
  {
116
- cwd: root,
117
108
  nodir: true,
118
109
  absolute: true
119
110
  }
@@ -0,0 +1,100 @@
1
+ import * as path from 'node:path';
2
+ import { readFileSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { glob } from 'glob';
5
+
6
+ const PROJECT_CACHE = /* @__PURE__ */ new Map();
7
+ class Project {
8
+ static load(root) {
9
+ const resolvedRoot = resolveRoot(root);
10
+ let project = PROJECT_CACHE.get(resolvedRoot);
11
+ if (project == null) {
12
+ project = new Project(resolvedRoot);
13
+ PROJECT_CACHE.set(resolvedRoot, project);
14
+ }
15
+ return project;
16
+ }
17
+ root;
18
+ get path() {
19
+ return this.root;
20
+ }
21
+ get name() {
22
+ return this.packageJSON.name;
23
+ }
24
+ #packageJSON;
25
+ get packageJSON() {
26
+ this.#packageJSON ??= new PackageJSON(this.root);
27
+ return this.#packageJSON;
28
+ }
29
+ constructor(root) {
30
+ this.root = resolveRoot(root);
31
+ }
32
+ resolve(...segments) {
33
+ return path.resolve(this.root, ...segments);
34
+ }
35
+ glob(pattern, options) {
36
+ return glob(pattern, {
37
+ ...options,
38
+ absolute: true,
39
+ cwd: this.root
40
+ });
41
+ }
42
+ }
43
+ class PackageJSON {
44
+ raw;
45
+ path;
46
+ get name() {
47
+ return this.raw.name;
48
+ }
49
+ constructor(rootOrPath) {
50
+ this.path = rootOrPath.endsWith("package.json") ? rootOrPath : path.join(rootOrPath, "package.json");
51
+ this.raw = JSON.parse(readFileSync(this.path, "utf8"));
52
+ }
53
+ }
54
+ function resolveRoot(root) {
55
+ return typeof root === "string" ? root : fileURLToPath(root);
56
+ }
57
+ async function sourceEntriesForProject(project) {
58
+ const { main, exports } = project.packageJSON.raw;
59
+ const entries = {};
60
+ if (typeof main === "string") {
61
+ entries["."] = await resolveTargetFileAsSource(main, project);
62
+ }
63
+ if (typeof exports === "string") {
64
+ entries["."] = await resolveTargetFileAsSource(exports, project);
65
+ return entries;
66
+ } else if (exports == null || typeof exports !== "object") {
67
+ return entries;
68
+ }
69
+ for (const [exportPath, exportCondition] of Object.entries(
70
+ exports
71
+ )) {
72
+ let targetFile = null;
73
+ if (exportCondition == null)
74
+ continue;
75
+ if (typeof exportCondition === "string") {
76
+ targetFile = exportCondition;
77
+ } else {
78
+ targetFile ??= exportCondition["source"] ?? exportCondition["quilt:source"] ?? exportCondition["quilt:esnext"] ?? Object.values(exportCondition).find(
79
+ (condition) => typeof condition === "string" && condition.startsWith("./build/")
80
+ );
81
+ }
82
+ if (targetFile == null)
83
+ continue;
84
+ const sourceFile = await resolveTargetFileAsSource(targetFile, project);
85
+ entries[exportPath] = sourceFile;
86
+ }
87
+ return entries;
88
+ }
89
+ async function resolveTargetFileAsSource(file, project) {
90
+ const sourceFile = file.includes("/build/") ? (await project.glob(
91
+ file.replace(/[/]build[/][^/]+[/]/, "/*/").replace(/(\.d\.ts|\.[\w]+)$/, ".*"),
92
+ {
93
+ absolute: true,
94
+ ignore: [project.resolve(file)]
95
+ }
96
+ ))[0] : project.resolve(file);
97
+ return sourceFile;
98
+ }
99
+
100
+ export { PackageJSON, Project, sourceEntriesForProject };