@atlaspack/core 2.12.1-canary.3354

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 (215) hide show
  1. package/LICENSE +201 -0
  2. package/index.d.ts +22 -0
  3. package/lib/AssetGraph.js +518 -0
  4. package/lib/Atlaspack.js +587 -0
  5. package/lib/AtlaspackConfig.js +298 -0
  6. package/lib/AtlaspackConfig.schema.js +125 -0
  7. package/lib/BundleGraph.js +1445 -0
  8. package/lib/CommittedAsset.js +133 -0
  9. package/lib/Dependency.js +88 -0
  10. package/lib/Environment.js +128 -0
  11. package/lib/InternalConfig.js +48 -0
  12. package/lib/PackagerRunner.js +519 -0
  13. package/lib/ReporterRunner.js +151 -0
  14. package/lib/RequestTracker.js +1089 -0
  15. package/lib/SymbolPropagation.js +625 -0
  16. package/lib/TargetDescriptor.schema.js +115 -0
  17. package/lib/Transformation.js +536 -0
  18. package/lib/UncommittedAsset.js +342 -0
  19. package/lib/Validation.js +215 -0
  20. package/lib/applyRuntimes.js +279 -0
  21. package/lib/assetUtils.js +189 -0
  22. package/lib/atlaspack-v3/AtlaspackV3.js +74 -0
  23. package/lib/atlaspack-v3/fs.js +30 -0
  24. package/lib/atlaspack-v3/index.js +19 -0
  25. package/lib/atlaspack-v3/jsCallable.js +15 -0
  26. package/lib/atlaspack-v3/plugins/Resolver.js +12 -0
  27. package/lib/atlaspack-v3/plugins/index.js +16 -0
  28. package/lib/atlaspack-v3/worker/index.js +3 -0
  29. package/lib/atlaspack-v3/worker/worker.js +30 -0
  30. package/lib/buildCache.js +18 -0
  31. package/lib/constants.js +21 -0
  32. package/lib/dumpGraphToGraphViz.js +206 -0
  33. package/lib/index.js +106 -0
  34. package/lib/loadAtlaspackPlugin.js +148 -0
  35. package/lib/loadDotEnv.js +54 -0
  36. package/lib/projectPath.js +86 -0
  37. package/lib/public/Asset.js +259 -0
  38. package/lib/public/Bundle.js +231 -0
  39. package/lib/public/BundleGraph.js +193 -0
  40. package/lib/public/BundleGroup.js +44 -0
  41. package/lib/public/Config.js +202 -0
  42. package/lib/public/Dependency.js +131 -0
  43. package/lib/public/Environment.js +244 -0
  44. package/lib/public/MutableBundleGraph.js +184 -0
  45. package/lib/public/PluginOptions.js +71 -0
  46. package/lib/public/Symbols.js +247 -0
  47. package/lib/public/Target.js +64 -0
  48. package/lib/registerCoreWithSerializer.js +45 -0
  49. package/lib/requests/AssetGraphRequest.js +427 -0
  50. package/lib/requests/AssetGraphRequestRust.js +187 -0
  51. package/lib/requests/AssetRequest.js +137 -0
  52. package/lib/requests/AtlaspackBuildRequest.js +78 -0
  53. package/lib/requests/AtlaspackConfigRequest.js +473 -0
  54. package/lib/requests/BundleGraphRequest.js +419 -0
  55. package/lib/requests/ConfigRequest.js +198 -0
  56. package/lib/requests/DevDepRequest.js +166 -0
  57. package/lib/requests/EntryRequest.js +295 -0
  58. package/lib/requests/PackageRequest.js +88 -0
  59. package/lib/requests/PathRequest.js +349 -0
  60. package/lib/requests/TargetRequest.js +1177 -0
  61. package/lib/requests/ValidationRequest.js +66 -0
  62. package/lib/requests/WriteBundleRequest.js +252 -0
  63. package/lib/requests/WriteBundlesRequest.js +153 -0
  64. package/lib/resolveOptions.js +234 -0
  65. package/lib/serializer.js +216 -0
  66. package/lib/serializerCore.browser.js +29 -0
  67. package/lib/serializerCore.js +16 -0
  68. package/lib/summarizeRequest.js +55 -0
  69. package/lib/types.js +35 -0
  70. package/lib/utils.js +160 -0
  71. package/lib/worker.js +170 -0
  72. package/package.json +59 -0
  73. package/src/AssetGraph.js +646 -0
  74. package/src/Atlaspack.js +632 -0
  75. package/src/AtlaspackConfig.js +490 -0
  76. package/src/AtlaspackConfig.schema.js +141 -0
  77. package/src/BundleGraph.js +2193 -0
  78. package/src/CommittedAsset.js +143 -0
  79. package/src/Dependency.js +142 -0
  80. package/src/Environment.js +151 -0
  81. package/src/InternalConfig.js +72 -0
  82. package/src/PackagerRunner.js +790 -0
  83. package/src/ReporterRunner.js +158 -0
  84. package/src/RequestTracker.js +1697 -0
  85. package/src/SymbolPropagation.js +794 -0
  86. package/src/TargetDescriptor.schema.js +136 -0
  87. package/src/Transformation.js +752 -0
  88. package/src/UncommittedAsset.js +426 -0
  89. package/src/Validation.js +223 -0
  90. package/src/applyRuntimes.js +341 -0
  91. package/src/assetUtils.js +254 -0
  92. package/src/atlaspack-v3/AtlaspackV3.js +73 -0
  93. package/src/atlaspack-v3/fs.js +36 -0
  94. package/src/atlaspack-v3/index.js +5 -0
  95. package/src/atlaspack-v3/jsCallable.js +13 -0
  96. package/src/atlaspack-v3/plugins/Resolver.js +9 -0
  97. package/src/atlaspack-v3/plugins/index.js +3 -0
  98. package/src/atlaspack-v3/worker/index.js +8 -0
  99. package/src/atlaspack-v3/worker/worker.js +14 -0
  100. package/src/buildCache.js +15 -0
  101. package/src/constants.js +22 -0
  102. package/src/dumpGraphToGraphViz.js +244 -0
  103. package/src/index.js +22 -0
  104. package/src/loadAtlaspackPlugin.js +239 -0
  105. package/src/loadDotEnv.js +56 -0
  106. package/src/projectPath.js +87 -0
  107. package/src/public/Asset.js +359 -0
  108. package/src/public/Bundle.js +337 -0
  109. package/src/public/BundleGraph.js +335 -0
  110. package/src/public/BundleGroup.js +55 -0
  111. package/src/public/Config.js +261 -0
  112. package/src/public/Dependency.js +176 -0
  113. package/src/public/Environment.js +316 -0
  114. package/src/public/MutableBundleGraph.js +320 -0
  115. package/src/public/PluginOptions.js +99 -0
  116. package/src/public/Symbols.js +315 -0
  117. package/src/public/Target.js +71 -0
  118. package/src/registerCoreWithSerializer.js +34 -0
  119. package/src/requests/AssetGraphRequest.js +577 -0
  120. package/src/requests/AssetGraphRequestRust.js +222 -0
  121. package/src/requests/AssetRequest.js +179 -0
  122. package/src/requests/AtlaspackBuildRequest.js +109 -0
  123. package/src/requests/AtlaspackConfigRequest.js +709 -0
  124. package/src/requests/BundleGraphRequest.js +547 -0
  125. package/src/requests/ConfigRequest.js +287 -0
  126. package/src/requests/DevDepRequest.js +246 -0
  127. package/src/requests/EntryRequest.js +385 -0
  128. package/src/requests/PackageRequest.js +105 -0
  129. package/src/requests/PathRequest.js +454 -0
  130. package/src/requests/TargetRequest.js +1632 -0
  131. package/src/requests/ValidationRequest.js +79 -0
  132. package/src/requests/WriteBundleRequest.js +362 -0
  133. package/src/requests/WriteBundlesRequest.js +209 -0
  134. package/src/resolveOptions.js +278 -0
  135. package/src/serializer.js +255 -0
  136. package/src/serializerCore.browser.js +8 -0
  137. package/src/serializerCore.js +5 -0
  138. package/src/summarizeRequest.js +47 -0
  139. package/src/types.js +581 -0
  140. package/src/utils.js +211 -0
  141. package/src/worker.js +189 -0
  142. package/test/AssetGraph.test.js +679 -0
  143. package/test/Atlaspack.test.js +142 -0
  144. package/test/AtlaspackConfig.test.js +405 -0
  145. package/test/AtlaspackConfigRequest.test.js +993 -0
  146. package/test/BundleGraph.test.js +121 -0
  147. package/test/EntryRequest.test.js +215 -0
  148. package/test/Environment.test.js +99 -0
  149. package/test/InternalAsset.test.js +76 -0
  150. package/test/PackagerRunner.test.js +27 -0
  151. package/test/PublicAsset.test.js +40 -0
  152. package/test/PublicBundle.test.js +68 -0
  153. package/test/PublicDependency.test.js +22 -0
  154. package/test/PublicEnvironment.test.js +27 -0
  155. package/test/PublicMutableBundleGraph.test.js +192 -0
  156. package/test/RequestTracker.test.js +448 -0
  157. package/test/SymbolPropagation.test.js +716 -0
  158. package/test/TargetRequest.test.js +1715 -0
  159. package/test/fixtures/application-targets/package.json +3 -0
  160. package/test/fixtures/atlaspack/index.js +1 -0
  161. package/test/fixtures/atlaspack/other.js +3 -0
  162. package/test/fixtures/atlaspack/package.json +1 -0
  163. package/test/fixtures/atlaspack/yarn.lock +0 -0
  164. package/test/fixtures/bundle.js +10 -0
  165. package/test/fixtures/common-targets/package.json +24 -0
  166. package/test/fixtures/common-targets-ignore/package.json +13 -0
  167. package/test/fixtures/config/.atlaspackrc +6 -0
  168. package/test/fixtures/config/subfolder/.atlaspackrc +6 -0
  169. package/test/fixtures/config-extends-not-found/.atlaspackrc +3 -0
  170. package/test/fixtures/config-extends-not-found/.atlaspackrc-json5 +3 -0
  171. package/test/fixtures/config-extends-not-found/.atlaspackrc-multiple +3 -0
  172. package/test/fixtures/config-extends-not-found/.atlaspackrc-node-modules +3 -0
  173. package/test/fixtures/config-malformed/.atlaspackrc +3 -0
  174. package/test/fixtures/config-node-pipeline/.atlaspackrc +6 -0
  175. package/test/fixtures/config-plugin-not-found/.atlaspackrc +6 -0
  176. package/test/fixtures/context/package.json +8 -0
  177. package/test/fixtures/custom-format-infer-ext/package.json +6 -0
  178. package/test/fixtures/custom-format-infer-type/package.json +7 -0
  179. package/test/fixtures/custom-format-mismatch/package.json +8 -0
  180. package/test/fixtures/custom-targets/package.json +20 -0
  181. package/test/fixtures/custom-targets-distdir/package.json +11 -0
  182. package/test/fixtures/duplicate-targets/package.json +4 -0
  183. package/test/fixtures/glob-like/[entry].js +0 -0
  184. package/test/fixtures/invalid-distpath/package.json +11 -0
  185. package/test/fixtures/invalid-engines/package.json +12 -0
  186. package/test/fixtures/invalid-source-missing/package.json +5 -0
  187. package/test/fixtures/invalid-source-not-file/package.json +5 -0
  188. package/test/fixtures/invalid-source-not-file/src/index.js +1 -0
  189. package/test/fixtures/invalid-target-source-missing/package.json +9 -0
  190. package/test/fixtures/invalid-target-source-not-file/package.json +9 -0
  191. package/test/fixtures/invalid-target-source-not-file/src/index.js +1 -0
  192. package/test/fixtures/invalid-targets/package.json +19 -0
  193. package/test/fixtures/library-custom-scopehoist/package.json +9 -0
  194. package/test/fixtures/library-scopehoist/package.json +8 -0
  195. package/test/fixtures/local-plugin-config-pkg/.atlaspackrc +3 -0
  196. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/index.json +8 -0
  197. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/local-plugin.js +7 -0
  198. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/package.json +7 -0
  199. package/test/fixtures/main-format-mismatch/package.json +8 -0
  200. package/test/fixtures/main-global/package.json +8 -0
  201. package/test/fixtures/main-mjs/package.json +8 -0
  202. package/test/fixtures/module-a.js +1 -0
  203. package/test/fixtures/module-b.js +1 -0
  204. package/test/fixtures/plugins/local-plugin.js +7 -0
  205. package/test/fixtures/plugins/node_modules/atlaspack-transformer-bad-engines/index.js +7 -0
  206. package/test/fixtures/plugins/node_modules/atlaspack-transformer-bad-engines/package.json +7 -0
  207. package/test/fixtures/plugins/node_modules/atlaspack-transformer-no-engines/index.js +7 -0
  208. package/test/fixtures/plugins/node_modules/atlaspack-transformer-no-engines/package.json +4 -0
  209. package/test/fixtures/targets-default-distdir-none/package.json +5 -0
  210. package/test/fixtures/targets-default-distdir-one/package.json +8 -0
  211. package/test/fixtures/targets-default-distdir-two/package.json +18 -0
  212. package/test/requests/ConfigRequest.test.js +254 -0
  213. package/test/serializer.test.js +302 -0
  214. package/test/test-utils.js +80 -0
  215. package/test/utils.test.js +43 -0
@@ -0,0 +1,1632 @@
1
+ // @flow strict-local
2
+
3
+ import type {Diagnostic} from '@atlaspack/diagnostic';
4
+ import type {FileSystem} from '@atlaspack/fs';
5
+ import type {
6
+ Async,
7
+ Engines,
8
+ FilePath,
9
+ PackageJSON,
10
+ PackageTargetDescriptor,
11
+ TargetDescriptor,
12
+ OutputFormat,
13
+ } from '@atlaspack/types';
14
+ import type {StaticRunOpts, RunAPI} from '../RequestTracker';
15
+ import type {Entry, AtlaspackOptions, Target} from '../types';
16
+ import type {ConfigAndCachePath} from './AtlaspackConfigRequest';
17
+
18
+ import ThrowableDiagnostic, {
19
+ convertSourceLocationToHighlight,
20
+ generateJSONCodeHighlights,
21
+ getJSONSourceLocation,
22
+ encodeJSONKeyComponent,
23
+ md,
24
+ } from '@atlaspack/diagnostic';
25
+ import path from 'path';
26
+ import {
27
+ loadConfig,
28
+ resolveConfig,
29
+ hashObject,
30
+ validateSchema,
31
+ } from '@atlaspack/utils';
32
+ import logger from '@atlaspack/logger';
33
+ import {createEnvironment} from '../Environment';
34
+ import createAtlaspackConfigRequest, {
35
+ getCachedAtlaspackConfig,
36
+ } from './AtlaspackConfigRequest';
37
+ // $FlowFixMe
38
+ import browserslist from 'browserslist';
39
+ import {parse} from '@mischnic/json-sourcemap';
40
+ import invariant from 'assert';
41
+ import nullthrows from 'nullthrows';
42
+ import {
43
+ COMMON_TARGET_DESCRIPTOR_SCHEMA,
44
+ DESCRIPTOR_SCHEMA,
45
+ PACKAGE_DESCRIPTOR_SCHEMA,
46
+ ENGINES_SCHEMA,
47
+ } from '../TargetDescriptor.schema';
48
+ import {BROWSER_ENVS} from '../public/Environment';
49
+ import {optionsProxy, toInternalSourceLocation} from '../utils';
50
+ import {fromProjectPath, toProjectPath, joinProjectPath} from '../projectPath';
51
+ import {requestTypes} from '../RequestTracker';
52
+
53
+ type RunOpts<TResult> = {|
54
+ input: Entry,
55
+ ...StaticRunOpts<TResult>,
56
+ |};
57
+
58
+ const DEFAULT_DIST_DIRNAME = 'dist';
59
+ const JS_RE = /\.[mc]?js$/;
60
+ const JS_EXTENSIONS = ['.js', '.mjs', '.cjs'];
61
+ const COMMON_TARGETS = {
62
+ main: {
63
+ match: JS_RE,
64
+ extensions: JS_EXTENSIONS,
65
+ },
66
+ module: {
67
+ // module field is always ESM. Don't allow .cjs extension here.
68
+ match: /\.m?js$/,
69
+ extensions: ['.js', '.mjs'],
70
+ },
71
+ browser: {
72
+ match: JS_RE,
73
+ extensions: JS_EXTENSIONS,
74
+ },
75
+ types: {
76
+ match: /\.d\.ts$/,
77
+ extensions: ['.d.ts'],
78
+ },
79
+ };
80
+
81
+ const DEFAULT_ENGINES = {
82
+ node: 'current',
83
+ browsers: [
84
+ 'last 1 Chrome version',
85
+ 'last 1 Safari version',
86
+ 'last 1 Firefox version',
87
+ 'last 1 Edge version',
88
+ ],
89
+ };
90
+
91
+ export type TargetRequest = {|
92
+ id: string,
93
+ +type: typeof requestTypes.target_request,
94
+ run: (RunOpts<TargetRequestResult>) => Async<TargetRequestResult>,
95
+ input: Entry,
96
+ |};
97
+
98
+ export type TargetRequestResult = Target[];
99
+
100
+ const type = 'target_request';
101
+
102
+ export default function createTargetRequest(input: Entry): TargetRequest {
103
+ return {
104
+ id: `${type}:${hashObject(input)}`,
105
+ type: requestTypes.target_request,
106
+ run,
107
+ input,
108
+ };
109
+ }
110
+
111
+ export function skipTarget(
112
+ targetName: string,
113
+ exclusiveTarget?: FilePath,
114
+ descriptorSource?: FilePath | Array<FilePath>,
115
+ ): boolean {
116
+ // We skip targets if they have a descriptor.source and don't match the current exclusiveTarget
117
+ // They will be handled by a separate resolvePackageTargets call from their Entry point
118
+ // but with exclusiveTarget set.
119
+
120
+ return exclusiveTarget == null
121
+ ? descriptorSource != null
122
+ : targetName !== exclusiveTarget;
123
+ }
124
+
125
+ async function run({input, api, options}) {
126
+ let targetResolver = new TargetResolver(
127
+ api,
128
+ optionsProxy(options, api.invalidateOnOptionChange),
129
+ );
130
+ let targets: TargetRequestResult = await targetResolver.resolve(
131
+ fromProjectPath(options.projectRoot, input.packagePath),
132
+ input.target,
133
+ );
134
+
135
+ assertTargetsAreNotEntries(targets, input, options);
136
+
137
+ let configResult = nullthrows(
138
+ await api.runRequest<null, ConfigAndCachePath>(
139
+ createAtlaspackConfigRequest(),
140
+ ),
141
+ );
142
+ let atlaspackConfig = getCachedAtlaspackConfig(configResult, options);
143
+
144
+ // Find named pipelines for each target.
145
+ let pipelineNames = new Set(atlaspackConfig.getNamedPipelines());
146
+ for (let target of targets) {
147
+ if (pipelineNames.has(target.name)) {
148
+ target.pipeline = target.name;
149
+ }
150
+ }
151
+
152
+ if (options.logLevel === 'verbose') {
153
+ await debugResolvedTargets(
154
+ input,
155
+ targets,
156
+ targetResolver.targetInfo,
157
+ options,
158
+ );
159
+ }
160
+
161
+ return targets;
162
+ }
163
+
164
+ type TargetInfo = {|
165
+ output: TargetKeyInfo,
166
+ engines: TargetKeyInfo,
167
+ context: TargetKeyInfo,
168
+ includeNodeModules: TargetKeyInfo,
169
+ outputFormat: TargetKeyInfo,
170
+ isLibrary: TargetKeyInfo,
171
+ shouldOptimize: TargetKeyInfo,
172
+ shouldScopeHoist: TargetKeyInfo,
173
+ |};
174
+
175
+ type TargetKeyInfo =
176
+ | {|
177
+ path: string,
178
+ type?: 'key' | 'value',
179
+ |}
180
+ | {|
181
+ inferred: string,
182
+ type?: 'key' | 'value',
183
+ message: string,
184
+ |}
185
+ | {|
186
+ message: string,
187
+ |};
188
+
189
+ export class TargetResolver {
190
+ fs: FileSystem;
191
+ api: RunAPI<Array<Target>>;
192
+ options: AtlaspackOptions;
193
+ targetInfo: Map<string, TargetInfo>;
194
+
195
+ constructor(api: RunAPI<Array<Target>>, options: AtlaspackOptions) {
196
+ this.api = api;
197
+ this.fs = options.inputFS;
198
+ this.options = options;
199
+ this.targetInfo = new Map();
200
+ }
201
+
202
+ async resolve(
203
+ rootDir: FilePath,
204
+ exclusiveTarget?: string,
205
+ ): Promise<Array<Target>> {
206
+ let optionTargets = this.options.targets;
207
+ if (exclusiveTarget != null && optionTargets == null) {
208
+ optionTargets = [exclusiveTarget];
209
+ }
210
+
211
+ let packageTargets: Map<string, Target | null> =
212
+ await this.resolvePackageTargets(rootDir, exclusiveTarget);
213
+ let targets: Array<Target>;
214
+ if (optionTargets) {
215
+ if (Array.isArray(optionTargets)) {
216
+ if (optionTargets.length === 0) {
217
+ throw new ThrowableDiagnostic({
218
+ diagnostic: {
219
+ message: `Targets option is an empty array`,
220
+ origin: '@atlaspack/core',
221
+ },
222
+ });
223
+ }
224
+
225
+ // Only build the intersection of the exclusive target and option targets.
226
+ if (exclusiveTarget != null) {
227
+ optionTargets = optionTargets.filter(
228
+ target => target === exclusiveTarget,
229
+ );
230
+ }
231
+
232
+ // If an array of strings is passed, it's a filter on the resolved package
233
+ // targets. Load them, and find the matching targets.
234
+ targets = optionTargets
235
+ .map(target => {
236
+ // null means skipped.
237
+ if (!packageTargets.has(target)) {
238
+ throw new ThrowableDiagnostic({
239
+ diagnostic: {
240
+ message: md`Could not find target with name "${target}"`,
241
+ origin: '@atlaspack/core',
242
+ },
243
+ });
244
+ }
245
+ return packageTargets.get(target);
246
+ })
247
+ .filter(Boolean);
248
+ } else {
249
+ // Otherwise, it's an object map of target descriptors (similar to those
250
+ // in package.json). Adapt them to native targets.
251
+ targets = Object.entries(optionTargets)
252
+ .map(([name, _descriptor]) => {
253
+ let {distDir, ...descriptor} = parseDescriptor(
254
+ name,
255
+ _descriptor,
256
+ null,
257
+ JSON.stringify({targets: optionTargets}, null, '\t'),
258
+ );
259
+ if (distDir == null) {
260
+ let optionTargetsString = JSON.stringify(
261
+ optionTargets,
262
+ null,
263
+ '\t',
264
+ );
265
+ throw new ThrowableDiagnostic({
266
+ diagnostic: {
267
+ message: md`Missing distDir for target "${name}"`,
268
+ origin: '@atlaspack/core',
269
+ codeFrames: [
270
+ {
271
+ code: optionTargetsString,
272
+ codeHighlights: generateJSONCodeHighlights(
273
+ optionTargetsString || '',
274
+ [
275
+ {
276
+ key: `/${name}`,
277
+ type: 'value',
278
+ },
279
+ ],
280
+ ),
281
+ },
282
+ ],
283
+ },
284
+ });
285
+ }
286
+ let target: Target = {
287
+ name,
288
+ distDir: toProjectPath(
289
+ this.options.projectRoot,
290
+ path.resolve(this.fs.cwd(), distDir),
291
+ ),
292
+ publicUrl:
293
+ descriptor.publicUrl ??
294
+ this.options.defaultTargetOptions.publicUrl,
295
+ env: createEnvironment({
296
+ engines: descriptor.engines,
297
+ context: descriptor.context,
298
+ isLibrary:
299
+ descriptor.isLibrary ??
300
+ this.options.defaultTargetOptions.isLibrary,
301
+ includeNodeModules: descriptor.includeNodeModules,
302
+ outputFormat:
303
+ descriptor.outputFormat ??
304
+ this.options.defaultTargetOptions.outputFormat,
305
+ shouldOptimize:
306
+ this.options.defaultTargetOptions.shouldOptimize &&
307
+ descriptor.optimize !== false,
308
+ shouldScopeHoist:
309
+ this.options.defaultTargetOptions.shouldScopeHoist &&
310
+ descriptor.scopeHoist !== false,
311
+ sourceMap: normalizeSourceMap(
312
+ this.options,
313
+ descriptor.sourceMap,
314
+ ),
315
+ }),
316
+ };
317
+
318
+ if (descriptor.distEntry != null) {
319
+ target.distEntry = descriptor.distEntry;
320
+ }
321
+
322
+ if (descriptor.source != null) {
323
+ target.source = descriptor.source;
324
+ }
325
+
326
+ return target;
327
+ })
328
+ .filter(
329
+ target => !skipTarget(target.name, exclusiveTarget, target.source),
330
+ );
331
+ }
332
+
333
+ let serve = this.options.serveOptions;
334
+ if (serve && targets.length > 0) {
335
+ // In serve mode, we only support a single browser target. If the user
336
+ // provided more than one, or the matching target is not a browser, throw.
337
+ if (targets.length > 1) {
338
+ throw new ThrowableDiagnostic({
339
+ diagnostic: {
340
+ message: `More than one target is not supported in serve mode`,
341
+ origin: '@atlaspack/core',
342
+ },
343
+ });
344
+ }
345
+ if (!BROWSER_ENVS.has(targets[0].env.context)) {
346
+ throw new ThrowableDiagnostic({
347
+ diagnostic: {
348
+ message: `Only browser targets are supported in serve mode`,
349
+ origin: '@atlaspack/core',
350
+ },
351
+ });
352
+ }
353
+ targets[0].distDir = toProjectPath(
354
+ this.options.projectRoot,
355
+ serve.distDir,
356
+ );
357
+ }
358
+ } else {
359
+ // Explicit targets were not provided. Either use a modern target for server
360
+ // mode, or simply use the package.json targets.
361
+ if (this.options.serveOptions) {
362
+ // In serve mode, we only support a single browser target. Since the user
363
+ // hasn't specified a target, use one targeting modern browsers for development
364
+ targets = [
365
+ {
366
+ name: 'default',
367
+ distDir: toProjectPath(
368
+ this.options.projectRoot,
369
+ this.options.serveOptions.distDir,
370
+ ),
371
+ publicUrl: this.options.defaultTargetOptions.publicUrl ?? '/',
372
+ env: createEnvironment({
373
+ context: 'browser',
374
+ engines: {
375
+ browsers: DEFAULT_ENGINES.browsers,
376
+ },
377
+ shouldOptimize: this.options.defaultTargetOptions.shouldOptimize,
378
+ outputFormat: this.options.defaultTargetOptions.outputFormat,
379
+ shouldScopeHoist:
380
+ this.options.defaultTargetOptions.shouldScopeHoist,
381
+ sourceMap: this.options.defaultTargetOptions.sourceMaps
382
+ ? {}
383
+ : undefined,
384
+ }),
385
+ },
386
+ ];
387
+ } else {
388
+ targets = Array.from(packageTargets.values())
389
+ .filter(Boolean)
390
+ .filter(descriptor => {
391
+ return (
392
+ descriptor &&
393
+ !skipTarget(descriptor.name, exclusiveTarget, descriptor.source)
394
+ );
395
+ });
396
+ }
397
+ }
398
+
399
+ return targets;
400
+ }
401
+
402
+ async resolvePackageTargets(
403
+ rootDir: FilePath,
404
+ exclusiveTarget?: string,
405
+ ): Promise<Map<string, Target | null>> {
406
+ let rootFile = path.join(rootDir, 'index');
407
+ let conf = await loadConfig(
408
+ this.fs,
409
+ rootFile,
410
+ ['package.json'],
411
+ this.options.projectRoot,
412
+ );
413
+
414
+ let rootFileProject = toProjectPath(this.options.projectRoot, rootFile);
415
+
416
+ // Invalidate whenever a package.json file is added.
417
+ this.api.invalidateOnFileCreate({
418
+ fileName: 'package.json',
419
+ aboveFilePath: rootFileProject,
420
+ });
421
+
422
+ let pkg;
423
+ let pkgContents;
424
+ let pkgFilePath: ?FilePath;
425
+ let pkgDir: FilePath;
426
+ let pkgMap;
427
+ if (conf) {
428
+ pkg = (conf.config: PackageJSON);
429
+ let pkgFile = conf.files[0];
430
+ if (pkgFile == null) {
431
+ throw new ThrowableDiagnostic({
432
+ diagnostic: {
433
+ message: md`Expected package.json file in ${rootDir}`,
434
+ origin: '@atlaspack/core',
435
+ },
436
+ });
437
+ }
438
+ let _pkgFilePath = (pkgFilePath = pkgFile.filePath); // For Flow
439
+ pkgDir = path.dirname(_pkgFilePath);
440
+ pkgContents = await this.fs.readFile(_pkgFilePath, 'utf8');
441
+ pkgMap = parse(pkgContents, undefined, {tabWidth: 1});
442
+
443
+ let pp = toProjectPath(this.options.projectRoot, _pkgFilePath);
444
+ this.api.invalidateOnFileUpdate(pp);
445
+ this.api.invalidateOnFileDelete(pp);
446
+ } else {
447
+ pkg = {};
448
+ pkgDir = this.fs.cwd();
449
+ }
450
+
451
+ let pkgTargets = pkg.targets || {};
452
+ let pkgEngines: Engines =
453
+ parseEngines(
454
+ pkg.engines,
455
+ pkgFilePath,
456
+ pkgContents,
457
+ '/engines',
458
+ 'Invalid engines in package.json',
459
+ ) || {};
460
+ let browsersLoc = {path: '/engines/browsers'};
461
+ let nodeLoc = {path: '/engines/node'};
462
+ if (pkgEngines.browsers == null) {
463
+ let env =
464
+ this.options.env.BROWSERSLIST_ENV ??
465
+ this.options.env.NODE_ENV ??
466
+ this.options.mode;
467
+
468
+ if (pkg.browserslist != null) {
469
+ let pkgBrowserslist = pkg.browserslist;
470
+ let browserslist =
471
+ typeof pkgBrowserslist === 'object' && !Array.isArray(pkgBrowserslist)
472
+ ? pkgBrowserslist[env]
473
+ : pkgBrowserslist;
474
+
475
+ pkgEngines = {
476
+ ...pkgEngines,
477
+ browsers: browserslist,
478
+ };
479
+
480
+ browsersLoc = {path: '/browserslist'};
481
+ } else {
482
+ let browserslistConfig = await resolveConfig(
483
+ this.fs,
484
+ path.join(rootDir, 'index'),
485
+ ['browserslist', '.browserslistrc'],
486
+ this.options.projectRoot,
487
+ );
488
+
489
+ this.api.invalidateOnFileCreate({
490
+ fileName: 'browserslist',
491
+ aboveFilePath: rootFileProject,
492
+ });
493
+
494
+ this.api.invalidateOnFileCreate({
495
+ fileName: '.browserslistrc',
496
+ aboveFilePath: rootFileProject,
497
+ });
498
+
499
+ if (browserslistConfig != null) {
500
+ let contents = await this.fs.readFile(browserslistConfig, 'utf8');
501
+ let config = browserslist.parseConfig(contents);
502
+ let browserslistBrowsers = config[env] || config.defaults;
503
+ let pp = toProjectPath(this.options.projectRoot, browserslistConfig);
504
+
505
+ if (browserslistBrowsers?.length > 0) {
506
+ pkgEngines = {
507
+ ...pkgEngines,
508
+ browsers: browserslistBrowsers,
509
+ };
510
+
511
+ browsersLoc = {
512
+ message: `(defined in ${path.relative(
513
+ process.cwd(),
514
+ browserslistConfig,
515
+ )})`,
516
+ };
517
+ }
518
+
519
+ // Invalidate whenever browserslist config file or relevant environment variables change
520
+ this.api.invalidateOnFileUpdate(pp);
521
+ this.api.invalidateOnFileDelete(pp);
522
+ this.api.invalidateOnEnvChange('BROWSERSLIST_ENV');
523
+ this.api.invalidateOnEnvChange('NODE_ENV');
524
+ }
525
+ }
526
+ }
527
+
528
+ let targets: Map<string, Target | null> = new Map();
529
+ let node = pkgEngines.node;
530
+ let browsers = pkgEngines.browsers;
531
+
532
+ let defaultEngines = this.options.defaultTargetOptions.engines;
533
+ let context = browsers ?? node == null ? 'browser' : 'node';
534
+ if (context === 'browser' && pkgEngines.browsers == null) {
535
+ pkgEngines = {
536
+ ...pkgEngines,
537
+ browsers: defaultEngines?.browsers ?? DEFAULT_ENGINES.browsers,
538
+ };
539
+ browsersLoc = {message: '(default)'};
540
+ } else if (context === 'node' && pkgEngines.node == null) {
541
+ pkgEngines = {
542
+ ...pkgEngines,
543
+ node: defaultEngines?.node ?? DEFAULT_ENGINES.node,
544
+ };
545
+ nodeLoc = {message: '(default)'};
546
+ }
547
+
548
+ // If there is a separate `browser` target, or an `engines.node` field but no browser targets, then
549
+ // the `main` and `module` targets refer to node, otherwise browser.
550
+ let mainContext =
551
+ pkg.browser ?? pkgTargets.browser ?? (node != null && browsers == null)
552
+ ? 'node'
553
+ : 'browser';
554
+ let mainContextLoc: TargetKeyInfo =
555
+ pkg.browser != null
556
+ ? {
557
+ inferred: '/browser',
558
+ message: '(because a browser field also exists)',
559
+ type: 'key',
560
+ }
561
+ : pkgTargets.browser
562
+ ? {
563
+ inferred: '/targets/browser',
564
+ message: '(because a browser target also exists)',
565
+ type: 'key',
566
+ }
567
+ : node != null && browsers == null
568
+ ? nodeLoc.path
569
+ ? {
570
+ inferred: nodeLoc.path,
571
+ message: '(because node engines were defined)',
572
+ type: 'key',
573
+ }
574
+ : nodeLoc
575
+ : {message: '(default)'};
576
+ let moduleContext =
577
+ pkg.browser ?? pkgTargets.browser ? 'browser' : mainContext;
578
+ let moduleContextLoc: TargetKeyInfo =
579
+ pkg.browser != null
580
+ ? {
581
+ inferred: '/browser',
582
+ message: '(because a browser field also exists)',
583
+ type: 'key',
584
+ }
585
+ : pkgTargets.browser
586
+ ? {
587
+ inferred: '/targets/browser',
588
+ message: '(becausea browser target also exists)',
589
+ type: 'key',
590
+ }
591
+ : mainContextLoc;
592
+
593
+ let getEnginesLoc = (targetName, descriptor): TargetKeyInfo => {
594
+ let enginesLoc = `/targets/${targetName}/engines`;
595
+ switch (context) {
596
+ case 'browser':
597
+ case 'web-worker':
598
+ case 'service-worker':
599
+ case 'worklet': {
600
+ if (descriptor.engines) {
601
+ return {path: enginesLoc + '/browsers'};
602
+ } else {
603
+ return browsersLoc;
604
+ }
605
+ }
606
+ case 'node': {
607
+ if (descriptor.engines) {
608
+ return {path: enginesLoc + '/node'};
609
+ } else {
610
+ return nodeLoc;
611
+ }
612
+ }
613
+ case 'electron-main':
614
+ case 'electron-renderer': {
615
+ if (descriptor.engines?.electron != null) {
616
+ return {path: enginesLoc + '/electron'};
617
+ } else if (pkgEngines?.electron != null) {
618
+ return {path: '/engines/electron'};
619
+ }
620
+ }
621
+ }
622
+
623
+ return {message: '(default)'};
624
+ };
625
+
626
+ for (let targetName in COMMON_TARGETS) {
627
+ let _targetDist;
628
+ let pointer;
629
+ if (
630
+ targetName === 'browser' &&
631
+ pkg[targetName] != null &&
632
+ typeof pkg[targetName] === 'object' &&
633
+ pkg.name
634
+ ) {
635
+ // The `browser` field can be a file path or an alias map.
636
+ _targetDist = pkg[targetName][pkg.name];
637
+ pointer = `/${targetName}/${encodeJSONKeyComponent(pkg.name)}`;
638
+ } else {
639
+ _targetDist = pkg[targetName];
640
+ pointer = `/${targetName}`;
641
+ }
642
+
643
+ // For Flow
644
+ let targetDist = _targetDist;
645
+ if (typeof targetDist === 'string' || pkgTargets[targetName]) {
646
+ let distDir;
647
+ let distEntry;
648
+ let loc;
649
+
650
+ invariant(pkgMap != null);
651
+
652
+ let _descriptor: mixed = pkgTargets[targetName] ?? {};
653
+ if (typeof targetDist === 'string') {
654
+ distDir = toProjectPath(
655
+ this.options.projectRoot,
656
+ path.resolve(pkgDir, path.dirname(targetDist)),
657
+ );
658
+ distEntry = path.basename(targetDist);
659
+ loc = {
660
+ filePath: nullthrows(pkgFilePath),
661
+ ...getJSONSourceLocation(pkgMap.pointers[pointer], 'value'),
662
+ };
663
+ } else {
664
+ distDir =
665
+ this.options.defaultTargetOptions.distDir ??
666
+ toProjectPath(
667
+ this.options.projectRoot,
668
+ path.join(pkgDir, DEFAULT_DIST_DIRNAME, targetName),
669
+ );
670
+ }
671
+
672
+ if (_descriptor == false) {
673
+ continue;
674
+ }
675
+
676
+ let descriptor = parseCommonTargetDescriptor(
677
+ targetName,
678
+ _descriptor,
679
+ pkgFilePath,
680
+ pkgContents,
681
+ );
682
+
683
+ if (skipTarget(targetName, exclusiveTarget, descriptor.source)) {
684
+ targets.set(targetName, null);
685
+ continue;
686
+ }
687
+
688
+ if (
689
+ distEntry != null &&
690
+ !COMMON_TARGETS[targetName].match.test(distEntry)
691
+ ) {
692
+ let contents: string =
693
+ typeof pkgContents === 'string'
694
+ ? pkgContents
695
+ : // $FlowFixMe
696
+ JSON.stringify(pkgContents, null, '\t');
697
+ // $FlowFixMe
698
+ let listFormat = new Intl.ListFormat('en-US', {type: 'disjunction'});
699
+ let extensions = listFormat.format(
700
+ COMMON_TARGETS[targetName].extensions,
701
+ );
702
+ let ext = path.extname(distEntry);
703
+ throw new ThrowableDiagnostic({
704
+ diagnostic: {
705
+ message: md`Unexpected output file type ${ext} in target "${targetName}"`,
706
+ origin: '@atlaspack/core',
707
+ codeFrames: [
708
+ {
709
+ language: 'json',
710
+ filePath: pkgFilePath ?? undefined,
711
+ code: contents,
712
+ codeHighlights: generateJSONCodeHighlights(contents, [
713
+ {
714
+ key: pointer,
715
+ type: 'value',
716
+ message: `File extension must be ${extensions}`,
717
+ },
718
+ ]),
719
+ },
720
+ ],
721
+ hints: [
722
+ `The "${targetName}" field is meant for libraries. If you meant to output a ${ext} file, either remove the "${targetName}" field or choose a different target name.`,
723
+ ],
724
+ documentationURL:
725
+ 'https://parceljs.org/features/targets/#library-targets',
726
+ },
727
+ });
728
+ }
729
+
730
+ if (descriptor.outputFormat === 'global') {
731
+ let contents: string =
732
+ typeof pkgContents === 'string'
733
+ ? pkgContents
734
+ : // $FlowFixMe
735
+ JSON.stringify(pkgContents, null, '\t');
736
+ throw new ThrowableDiagnostic({
737
+ diagnostic: {
738
+ message: md`The "global" output format is not supported in the "${targetName}" target.`,
739
+ origin: '@atlaspack/core',
740
+ codeFrames: [
741
+ {
742
+ language: 'json',
743
+ filePath: pkgFilePath ?? undefined,
744
+ code: contents,
745
+ codeHighlights: generateJSONCodeHighlights(contents, [
746
+ {
747
+ key: `/targets/${targetName}/outputFormat`,
748
+ type: 'value',
749
+ },
750
+ ]),
751
+ },
752
+ ],
753
+ hints: [
754
+ `The "${targetName}" field is meant for libraries. The outputFormat must be either "commonjs" or "esmodule". Either change or remove the declared outputFormat.`,
755
+ ],
756
+ documentationURL:
757
+ 'https://parceljs.org/features/targets/#library-targets',
758
+ },
759
+ });
760
+ }
761
+
762
+ let [inferredOutputFormat, inferredOutputFormatField] =
763
+ this.inferOutputFormat(
764
+ distEntry,
765
+ descriptor,
766
+ targetName,
767
+ pkg,
768
+ pkgFilePath,
769
+ pkgContents,
770
+ );
771
+
772
+ let outputFormat =
773
+ descriptor.outputFormat ??
774
+ this.options.defaultTargetOptions.outputFormat ??
775
+ inferredOutputFormat ??
776
+ (targetName === 'module' ? 'esmodule' : 'commonjs');
777
+ let isModule = outputFormat === 'esmodule';
778
+
779
+ if (
780
+ targetName === 'main' &&
781
+ outputFormat === 'esmodule' &&
782
+ inferredOutputFormat !== 'esmodule'
783
+ ) {
784
+ let contents: string =
785
+ typeof pkgContents === 'string'
786
+ ? pkgContents
787
+ : // $FlowFixMe
788
+ JSON.stringify(pkgContents, null, '\t');
789
+ throw new ThrowableDiagnostic({
790
+ diagnostic: {
791
+ // prettier-ignore
792
+ message: md`Output format "esmodule" cannot be used in the "main" target without a .mjs extension or "type": "module" field.`,
793
+ origin: '@atlaspack/core',
794
+ codeFrames: [
795
+ {
796
+ language: 'json',
797
+ filePath: pkgFilePath ?? undefined,
798
+ code: contents,
799
+ codeHighlights: generateJSONCodeHighlights(contents, [
800
+ {
801
+ key: `/targets/${targetName}/outputFormat`,
802
+ type: 'value',
803
+ message: 'Declared output format defined here',
804
+ },
805
+ {
806
+ key: '/main',
807
+ type: 'value',
808
+ message: 'Inferred output format defined here',
809
+ },
810
+ ]),
811
+ },
812
+ ],
813
+ hints: [
814
+ `Either change the output file extension to .mjs, add "type": "module" to package.json, or remove the declared outputFormat.`,
815
+ ],
816
+ documentationURL:
817
+ 'https://parceljs.org/features/targets/#library-targets',
818
+ },
819
+ });
820
+ }
821
+
822
+ if (descriptor.scopeHoist === false) {
823
+ let contents: string =
824
+ typeof pkgContents === 'string'
825
+ ? pkgContents
826
+ : // $FlowFixMe
827
+ JSON.stringify(pkgContents, null, '\t');
828
+ throw new ThrowableDiagnostic({
829
+ diagnostic: {
830
+ message: 'Scope hoisting cannot be disabled for library targets.',
831
+ origin: '@atlaspack/core',
832
+ codeFrames: [
833
+ {
834
+ language: 'json',
835
+ filePath: pkgFilePath ?? undefined,
836
+ code: contents,
837
+ codeHighlights: generateJSONCodeHighlights(contents, [
838
+ {
839
+ key: `/targets/${targetName}/scopeHoist`,
840
+ type: 'value',
841
+ },
842
+ ]),
843
+ },
844
+ ],
845
+ hints: [
846
+ `The "${targetName}" target is meant for libraries. Either remove the "scopeHoist" option, or use a different target name.`,
847
+ ],
848
+ documentationURL:
849
+ 'https://parceljs.org/features/targets/#library-targets',
850
+ },
851
+ });
852
+ }
853
+
854
+ let context =
855
+ descriptor.context ??
856
+ (targetName === 'browser'
857
+ ? 'browser'
858
+ : isModule
859
+ ? moduleContext
860
+ : mainContext);
861
+
862
+ targets.set(targetName, {
863
+ name: targetName,
864
+ distDir,
865
+ distEntry,
866
+ publicUrl:
867
+ descriptor.publicUrl ?? this.options.defaultTargetOptions.publicUrl,
868
+ env: createEnvironment({
869
+ engines: descriptor.engines ?? pkgEngines,
870
+ context,
871
+ includeNodeModules: descriptor.includeNodeModules ?? false,
872
+ outputFormat,
873
+ isLibrary: true,
874
+ shouldOptimize:
875
+ this.options.defaultTargetOptions.shouldOptimize &&
876
+ descriptor.optimize === true,
877
+ shouldScopeHoist: true,
878
+ sourceMap: normalizeSourceMap(this.options, descriptor.sourceMap),
879
+ }),
880
+ loc: toInternalSourceLocation(this.options.projectRoot, loc),
881
+ });
882
+
883
+ this.targetInfo.set(targetName, {
884
+ output: {path: pointer},
885
+ engines: getEnginesLoc(targetName, descriptor),
886
+ context: descriptor.context
887
+ ? {path: `/targets/${targetName}/context`}
888
+ : targetName === 'browser'
889
+ ? {
890
+ message: '(inferred from target name)',
891
+ inferred: pointer,
892
+ type: 'key',
893
+ }
894
+ : isModule
895
+ ? moduleContextLoc
896
+ : mainContextLoc,
897
+ includeNodeModules: descriptor.includeNodeModules
898
+ ? {path: `/targets/${targetName}/includeNodeModules`, type: 'key'}
899
+ : {message: '(default)'},
900
+ outputFormat: descriptor.outputFormat
901
+ ? {path: `/targets/${targetName}/outputFormat`}
902
+ : inferredOutputFormatField === '/type'
903
+ ? {
904
+ message: `(inferred from package.json#type)`,
905
+ inferred: inferredOutputFormatField,
906
+ }
907
+ : inferredOutputFormatField != null
908
+ ? {
909
+ message: `(inferred from file extension)`,
910
+ inferred: inferredOutputFormatField,
911
+ }
912
+ : {message: '(default)'},
913
+ isLibrary: {message: '(default)'},
914
+ shouldOptimize: descriptor.optimize
915
+ ? {path: `/targets/${targetName}/optimize`}
916
+ : {message: '(default)'},
917
+ shouldScopeHoist: {message: '(default)'},
918
+ });
919
+ }
920
+ }
921
+
922
+ let customTargets = (Object.keys(pkgTargets): Array<string>).filter(
923
+ targetName => !COMMON_TARGETS[targetName],
924
+ );
925
+
926
+ // Custom targets
927
+ for (let targetName of customTargets) {
928
+ let distPath: mixed = pkg[targetName];
929
+ let distDir;
930
+ let distEntry;
931
+ let loc;
932
+ let pointer;
933
+ if (distPath == null) {
934
+ distDir =
935
+ fromProjectPath(
936
+ this.options.projectRoot,
937
+ this.options.defaultTargetOptions.distDir,
938
+ ) ?? path.join(pkgDir, DEFAULT_DIST_DIRNAME);
939
+ if (customTargets.length >= 2) {
940
+ distDir = path.join(distDir, targetName);
941
+ }
942
+ invariant(pkgMap != null);
943
+ invariant(typeof pkgFilePath === 'string');
944
+ loc = {
945
+ filePath: pkgFilePath,
946
+ ...getJSONSourceLocation(
947
+ pkgMap.pointers[`/targets/${targetName}`],
948
+ 'key',
949
+ ),
950
+ };
951
+ } else {
952
+ if (typeof distPath !== 'string') {
953
+ let contents: string =
954
+ typeof pkgContents === 'string'
955
+ ? pkgContents
956
+ : // $FlowFixMe
957
+ JSON.stringify(pkgContents, null, '\t');
958
+ throw new ThrowableDiagnostic({
959
+ diagnostic: {
960
+ message: md`Invalid distPath for target "${targetName}"`,
961
+ origin: '@atlaspack/core',
962
+ codeFrames: [
963
+ {
964
+ language: 'json',
965
+ filePath: pkgFilePath ?? undefined,
966
+ code: contents,
967
+ codeHighlights: generateJSONCodeHighlights(contents, [
968
+ {
969
+ key: `/${targetName}`,
970
+ type: 'value',
971
+ message: 'Expected type string',
972
+ },
973
+ ]),
974
+ },
975
+ ],
976
+ },
977
+ });
978
+ }
979
+ distDir = path.resolve(pkgDir, path.dirname(distPath));
980
+ distEntry = path.basename(distPath);
981
+
982
+ invariant(typeof pkgFilePath === 'string');
983
+ invariant(pkgMap != null);
984
+ loc = {
985
+ filePath: pkgFilePath,
986
+ ...getJSONSourceLocation(pkgMap.pointers[`/${targetName}`], 'value'),
987
+ };
988
+ pointer = `/${targetName}`;
989
+ }
990
+
991
+ if (targetName in pkgTargets) {
992
+ let descriptor = parsePackageDescriptor(
993
+ targetName,
994
+ pkgTargets[targetName],
995
+ pkgFilePath,
996
+ pkgContents,
997
+ );
998
+ let pkgDir = path.dirname(nullthrows(pkgFilePath));
999
+ if (skipTarget(targetName, exclusiveTarget, descriptor.source)) {
1000
+ targets.set(targetName, null);
1001
+ continue;
1002
+ }
1003
+
1004
+ let [inferredOutputFormat, inferredOutputFormatField] =
1005
+ this.inferOutputFormat(
1006
+ distEntry,
1007
+ descriptor,
1008
+ targetName,
1009
+ pkg,
1010
+ pkgFilePath,
1011
+ pkgContents,
1012
+ );
1013
+
1014
+ if (descriptor.scopeHoist === false && descriptor.isLibrary) {
1015
+ let contents: string =
1016
+ typeof pkgContents === 'string'
1017
+ ? pkgContents
1018
+ : // $FlowFixMe
1019
+ JSON.stringify(pkgContents, null, '\t');
1020
+ throw new ThrowableDiagnostic({
1021
+ diagnostic: {
1022
+ message: 'Scope hoisting cannot be disabled for library targets.',
1023
+ origin: '@atlaspack/core',
1024
+ codeFrames: [
1025
+ {
1026
+ language: 'json',
1027
+ filePath: pkgFilePath ?? undefined,
1028
+ code: contents,
1029
+ codeHighlights: generateJSONCodeHighlights(contents, [
1030
+ {
1031
+ key: `/targets/${targetName}/scopeHoist`,
1032
+ type: 'value',
1033
+ },
1034
+ {
1035
+ key: `/targets/${targetName}/isLibrary`,
1036
+ type: 'value',
1037
+ },
1038
+ ]),
1039
+ },
1040
+ ],
1041
+ hints: [`Either remove the "scopeHoist" or "isLibrary" option.`],
1042
+ documentationURL:
1043
+ 'https://parceljs.org/features/targets/#library-targets',
1044
+ },
1045
+ });
1046
+ }
1047
+
1048
+ let isLibrary =
1049
+ descriptor.isLibrary ??
1050
+ this.options.defaultTargetOptions.isLibrary ??
1051
+ false;
1052
+ let shouldScopeHoist = isLibrary
1053
+ ? true
1054
+ : this.options.defaultTargetOptions.shouldScopeHoist;
1055
+
1056
+ targets.set(targetName, {
1057
+ name: targetName,
1058
+ distDir: toProjectPath(
1059
+ this.options.projectRoot,
1060
+ descriptor.distDir != null
1061
+ ? path.resolve(pkgDir, descriptor.distDir)
1062
+ : distDir,
1063
+ ),
1064
+ distEntry,
1065
+ publicUrl:
1066
+ descriptor.publicUrl ?? this.options.defaultTargetOptions.publicUrl,
1067
+ env: createEnvironment({
1068
+ engines: descriptor.engines ?? pkgEngines,
1069
+ context: descriptor.context,
1070
+ includeNodeModules: descriptor.includeNodeModules,
1071
+ outputFormat:
1072
+ descriptor.outputFormat ??
1073
+ this.options.defaultTargetOptions.outputFormat ??
1074
+ inferredOutputFormat ??
1075
+ undefined,
1076
+ isLibrary,
1077
+ shouldOptimize:
1078
+ this.options.defaultTargetOptions.shouldOptimize &&
1079
+ // Libraries are not optimized by default, users must explicitly configure this.
1080
+ (isLibrary
1081
+ ? descriptor.optimize === true
1082
+ : descriptor.optimize !== false),
1083
+ shouldScopeHoist:
1084
+ shouldScopeHoist && descriptor.scopeHoist !== false,
1085
+ sourceMap: normalizeSourceMap(this.options, descriptor.sourceMap),
1086
+ }),
1087
+ loc: toInternalSourceLocation(this.options.projectRoot, loc),
1088
+ });
1089
+
1090
+ this.targetInfo.set(targetName, {
1091
+ output: pointer != null ? {path: pointer} : {message: '(default)'},
1092
+ engines: getEnginesLoc(targetName, descriptor),
1093
+ context: descriptor.context
1094
+ ? {path: `/targets/${targetName}/context`}
1095
+ : {message: '(default)'},
1096
+ includeNodeModules: descriptor.includeNodeModules
1097
+ ? {path: `/targets/${targetName}/includeNodeModules`, type: 'key'}
1098
+ : {message: '(default)'},
1099
+ outputFormat: descriptor.outputFormat
1100
+ ? {path: `/targets/${targetName}/outputFormat`}
1101
+ : inferredOutputFormatField === '/type'
1102
+ ? {
1103
+ message: `(inferred from package.json#type)`,
1104
+ inferred: inferredOutputFormatField,
1105
+ }
1106
+ : inferredOutputFormatField != null
1107
+ ? {
1108
+ message: `(inferred from file extension)`,
1109
+ inferred: inferredOutputFormatField,
1110
+ }
1111
+ : {message: '(default)'},
1112
+ isLibrary:
1113
+ descriptor.isLibrary != null
1114
+ ? {path: `/targets/${targetName}/isLibrary`}
1115
+ : {message: '(default)'},
1116
+ shouldOptimize:
1117
+ descriptor.optimize != null
1118
+ ? {path: `/targets/${targetName}/optimize`}
1119
+ : {message: '(default)'},
1120
+ shouldScopeHoist:
1121
+ descriptor.scopeHoist != null
1122
+ ? {path: `/targets/${targetName}/scopeHoist`}
1123
+ : {message: '(default)'},
1124
+ });
1125
+ }
1126
+ }
1127
+
1128
+ // If no explicit targets were defined, add a default.
1129
+ if (targets.size === 0) {
1130
+ targets.set('default', {
1131
+ name: 'default',
1132
+ distDir:
1133
+ this.options.defaultTargetOptions.distDir ??
1134
+ toProjectPath(
1135
+ this.options.projectRoot,
1136
+ path.join(pkgDir, DEFAULT_DIST_DIRNAME),
1137
+ ),
1138
+ publicUrl: this.options.defaultTargetOptions.publicUrl,
1139
+ env: createEnvironment({
1140
+ engines: pkgEngines,
1141
+ context,
1142
+ outputFormat: this.options.defaultTargetOptions.outputFormat,
1143
+ isLibrary: this.options.defaultTargetOptions.isLibrary,
1144
+ shouldOptimize: this.options.defaultTargetOptions.shouldOptimize,
1145
+ shouldScopeHoist:
1146
+ this.options.defaultTargetOptions.shouldScopeHoist ??
1147
+ (this.options.mode === 'production' &&
1148
+ !this.options.defaultTargetOptions.isLibrary),
1149
+ sourceMap: this.options.defaultTargetOptions.sourceMaps
1150
+ ? {}
1151
+ : undefined,
1152
+ }),
1153
+ });
1154
+ }
1155
+
1156
+ assertNoDuplicateTargets(this.options, targets, pkgFilePath, pkgContents);
1157
+
1158
+ return targets;
1159
+ }
1160
+
1161
+ inferOutputFormat(
1162
+ distEntry: ?FilePath,
1163
+ descriptor: PackageTargetDescriptor,
1164
+ targetName: string,
1165
+ pkg: PackageJSON,
1166
+ pkgFilePath: ?FilePath,
1167
+ pkgContents: ?string,
1168
+ ): [?OutputFormat, ?string] {
1169
+ // Infer the outputFormat based on package.json properties.
1170
+ // If the extension is .mjs it's always a module.
1171
+ // If the extension is .cjs, it's always commonjs.
1172
+ // If the "type" field is set to "module" and the extension is .js, it's a module.
1173
+ let ext = distEntry != null ? path.extname(distEntry) : null;
1174
+ let inferredOutputFormat, inferredOutputFormatField;
1175
+ switch (ext) {
1176
+ case '.mjs':
1177
+ inferredOutputFormat = 'esmodule';
1178
+ inferredOutputFormatField = `/${targetName}`;
1179
+ break;
1180
+ case '.cjs':
1181
+ inferredOutputFormat = 'commonjs';
1182
+ inferredOutputFormatField = `/${targetName}`;
1183
+ break;
1184
+ case '.js':
1185
+ if (pkg.type === 'module') {
1186
+ inferredOutputFormat = 'esmodule';
1187
+ inferredOutputFormatField = '/type';
1188
+ }
1189
+ break;
1190
+ }
1191
+
1192
+ if (
1193
+ descriptor.outputFormat &&
1194
+ inferredOutputFormat &&
1195
+ descriptor.outputFormat !== inferredOutputFormat
1196
+ ) {
1197
+ let contents: string =
1198
+ typeof pkgContents === 'string'
1199
+ ? pkgContents
1200
+ : // $FlowFixMe
1201
+ JSON.stringify(pkgContents, null, '\t');
1202
+ let expectedExtensions;
1203
+ switch (descriptor.outputFormat) {
1204
+ case 'esmodule':
1205
+ expectedExtensions = ['.mjs', '.js'];
1206
+ break;
1207
+ case 'commonjs':
1208
+ expectedExtensions = ['.cjs', '.js'];
1209
+ break;
1210
+ case 'global':
1211
+ expectedExtensions = ['.js'];
1212
+ break;
1213
+ }
1214
+ // $FlowFixMe
1215
+ let listFormat = new Intl.ListFormat('en-US', {type: 'disjunction'});
1216
+ throw new ThrowableDiagnostic({
1217
+ diagnostic: {
1218
+ message: md`Declared output format "${descriptor.outputFormat}" does not match expected output format "${inferredOutputFormat}".`,
1219
+ origin: '@atlaspack/core',
1220
+ codeFrames: [
1221
+ {
1222
+ language: 'json',
1223
+ filePath: pkgFilePath ?? undefined,
1224
+ code: contents,
1225
+ codeHighlights: generateJSONCodeHighlights(contents, [
1226
+ {
1227
+ key: `/targets/${targetName}/outputFormat`,
1228
+ type: 'value',
1229
+ message: 'Declared output format defined here',
1230
+ },
1231
+ {
1232
+ key: nullthrows(inferredOutputFormatField),
1233
+ type: 'value',
1234
+ message: 'Inferred output format defined here',
1235
+ },
1236
+ ]),
1237
+ },
1238
+ ],
1239
+ hints: [
1240
+ inferredOutputFormatField === '/type'
1241
+ ? 'Either remove the target\'s declared "outputFormat" or remove the "type" field.'
1242
+ : `Either remove the target's declared "outputFormat" or change the extension to ${listFormat.format(
1243
+ expectedExtensions,
1244
+ )}.`,
1245
+ ],
1246
+ documentationURL:
1247
+ 'https://parceljs.org/features/targets/#library-targets',
1248
+ },
1249
+ });
1250
+ }
1251
+
1252
+ return [inferredOutputFormat, inferredOutputFormatField];
1253
+ }
1254
+ }
1255
+
1256
+ function parseEngines(
1257
+ engines: mixed,
1258
+ pkgPath: ?FilePath,
1259
+ pkgContents: ?string,
1260
+ prependKey: string,
1261
+ message: string,
1262
+ ): Engines | typeof undefined {
1263
+ if (engines === undefined) {
1264
+ return engines;
1265
+ } else {
1266
+ validateSchema.diagnostic(
1267
+ ENGINES_SCHEMA,
1268
+ {data: engines, source: pkgContents, filePath: pkgPath, prependKey},
1269
+ '@atlaspack/core',
1270
+ message,
1271
+ );
1272
+ // $FlowFixMe we just verified this
1273
+ return engines;
1274
+ }
1275
+ }
1276
+
1277
+ function parseDescriptor(
1278
+ targetName: string,
1279
+ descriptor: mixed,
1280
+ pkgPath: ?FilePath,
1281
+ pkgContents: ?string,
1282
+ ): TargetDescriptor {
1283
+ validateSchema.diagnostic(
1284
+ DESCRIPTOR_SCHEMA,
1285
+ {
1286
+ data: descriptor,
1287
+ source: pkgContents,
1288
+ filePath: pkgPath,
1289
+ prependKey: `/targets/${targetName}`,
1290
+ },
1291
+ '@atlaspack/core',
1292
+ `Invalid target descriptor for target "${targetName}"`,
1293
+ );
1294
+
1295
+ // $FlowFixMe we just verified this
1296
+ return descriptor;
1297
+ }
1298
+
1299
+ function parsePackageDescriptor(
1300
+ targetName: string,
1301
+ descriptor: mixed,
1302
+ pkgPath: ?FilePath,
1303
+ pkgContents: ?string,
1304
+ ): PackageTargetDescriptor {
1305
+ validateSchema.diagnostic(
1306
+ PACKAGE_DESCRIPTOR_SCHEMA,
1307
+ {
1308
+ data: descriptor,
1309
+ source: pkgContents,
1310
+ filePath: pkgPath,
1311
+ prependKey: `/targets/${targetName}`,
1312
+ },
1313
+ '@atlaspack/core',
1314
+ `Invalid target descriptor for target "${targetName}"`,
1315
+ );
1316
+ // $FlowFixMe we just verified this
1317
+ return descriptor;
1318
+ }
1319
+
1320
+ function parseCommonTargetDescriptor(
1321
+ targetName: string,
1322
+ descriptor: mixed,
1323
+ pkgPath: ?FilePath,
1324
+ pkgContents: ?string,
1325
+ ): PackageTargetDescriptor {
1326
+ validateSchema.diagnostic(
1327
+ COMMON_TARGET_DESCRIPTOR_SCHEMA,
1328
+ {
1329
+ data: descriptor,
1330
+ source: pkgContents,
1331
+ filePath: pkgPath,
1332
+ prependKey: `/targets/${targetName}`,
1333
+ },
1334
+ '@atlaspack/core',
1335
+ `Invalid target descriptor for target "${targetName}"`,
1336
+ );
1337
+
1338
+ // $FlowFixMe we just verified this
1339
+ return descriptor;
1340
+ }
1341
+
1342
+ function assertNoDuplicateTargets(options, targets, pkgFilePath, pkgContents) {
1343
+ // Detect duplicate targets by destination path and provide a nice error.
1344
+ // Without this, an assertion is thrown much later after naming the bundles and finding duplicates.
1345
+ let targetsByPath: Map<string, Array<string>> = new Map();
1346
+ for (let target of targets.values()) {
1347
+ if (!target) {
1348
+ continue;
1349
+ }
1350
+
1351
+ let {distEntry} = target;
1352
+ if (distEntry != null) {
1353
+ let distPath = path.join(
1354
+ fromProjectPath(options.projectRoot, target.distDir),
1355
+ distEntry,
1356
+ );
1357
+ if (!targetsByPath.has(distPath)) {
1358
+ targetsByPath.set(distPath, []);
1359
+ }
1360
+ targetsByPath.get(distPath)?.push(target.name);
1361
+ }
1362
+ }
1363
+
1364
+ let diagnostics: Array<Diagnostic> = [];
1365
+ for (let [targetPath, targetNames] of targetsByPath) {
1366
+ if (targetNames.length > 1 && pkgContents != null && pkgFilePath != null) {
1367
+ diagnostics.push({
1368
+ message: md`Multiple targets have the same destination path "${path.relative(
1369
+ path.dirname(pkgFilePath),
1370
+ targetPath,
1371
+ )}"`,
1372
+ origin: '@atlaspack/core',
1373
+ codeFrames: [
1374
+ {
1375
+ language: 'json',
1376
+ filePath: pkgFilePath || undefined,
1377
+ code: pkgContents,
1378
+ codeHighlights: generateJSONCodeHighlights(
1379
+ pkgContents,
1380
+ targetNames.map(t => ({
1381
+ key: `/${t}`,
1382
+ type: 'value',
1383
+ })),
1384
+ ),
1385
+ },
1386
+ ],
1387
+ });
1388
+ }
1389
+ }
1390
+
1391
+ if (diagnostics.length > 0) {
1392
+ // Only add hints to the last diagnostic so it isn't duplicated on each one
1393
+ diagnostics[diagnostics.length - 1].hints = [
1394
+ 'Try removing the duplicate targets, or changing the destination paths.',
1395
+ ];
1396
+
1397
+ throw new ThrowableDiagnostic({
1398
+ diagnostic: diagnostics,
1399
+ });
1400
+ }
1401
+ }
1402
+
1403
+ function normalizeSourceMap(options: AtlaspackOptions, sourceMap) {
1404
+ if (options.defaultTargetOptions.sourceMaps) {
1405
+ if (typeof sourceMap === 'boolean') {
1406
+ return sourceMap ? {} : undefined;
1407
+ } else {
1408
+ return sourceMap ?? {};
1409
+ }
1410
+ } else {
1411
+ return undefined;
1412
+ }
1413
+ }
1414
+
1415
+ function assertTargetsAreNotEntries(
1416
+ targets: Array<Target>,
1417
+ input: Entry,
1418
+ options: AtlaspackOptions,
1419
+ ) {
1420
+ for (const target of targets) {
1421
+ if (
1422
+ target.distEntry != null &&
1423
+ joinProjectPath(target.distDir, target.distEntry) === input.filePath
1424
+ ) {
1425
+ let loc = target.loc;
1426
+ let relativeEntry = path.relative(
1427
+ process.cwd(),
1428
+ fromProjectPath(options.projectRoot, input.filePath),
1429
+ );
1430
+ let codeFrames = [];
1431
+ if (loc) {
1432
+ codeFrames.push({
1433
+ filePath: fromProjectPath(options.projectRoot, loc.filePath),
1434
+ codeHighlights: [
1435
+ convertSourceLocationToHighlight(loc, 'Target defined here'),
1436
+ ],
1437
+ });
1438
+
1439
+ let inputLoc = input.loc;
1440
+ if (inputLoc) {
1441
+ let highlight = convertSourceLocationToHighlight(
1442
+ inputLoc,
1443
+ 'Entry defined here',
1444
+ );
1445
+
1446
+ if (inputLoc.filePath === loc.filePath) {
1447
+ codeFrames[0].codeHighlights.push(highlight);
1448
+ } else {
1449
+ codeFrames.push({
1450
+ filePath: fromProjectPath(options.projectRoot, inputLoc.filePath),
1451
+ codeHighlights: [highlight],
1452
+ });
1453
+ }
1454
+ }
1455
+ }
1456
+
1457
+ throw new ThrowableDiagnostic({
1458
+ diagnostic: {
1459
+ origin: '@atlaspack/core',
1460
+ message: `Target "${target.name}" is configured to overwrite entry "${relativeEntry}".`,
1461
+ codeFrames,
1462
+ hints: [
1463
+ (COMMON_TARGETS[target.name]
1464
+ ? `The "${target.name}" field is an _output_ file path so that your build can be consumed by other tools. `
1465
+ : '') +
1466
+ `Change the "${target.name}" field to point to an output file rather than your source code.`,
1467
+ ],
1468
+ documentationURL: 'https://parceljs.org/features/targets/',
1469
+ },
1470
+ });
1471
+ }
1472
+ }
1473
+ }
1474
+
1475
+ async function debugResolvedTargets(input, targets, targetInfo, options) {
1476
+ for (let target of targets) {
1477
+ let info = targetInfo.get(target.name);
1478
+ let loc = target.loc;
1479
+ if (!loc || !info) {
1480
+ continue;
1481
+ }
1482
+
1483
+ let output = fromProjectPath(options.projectRoot, target.distDir);
1484
+ if (target.distEntry != null) {
1485
+ output = path.join(output, target.distEntry);
1486
+ }
1487
+
1488
+ // Resolve relevant engines for context.
1489
+ let engines;
1490
+ switch (target.env.context) {
1491
+ case 'browser':
1492
+ case 'web-worker':
1493
+ case 'service-worker':
1494
+ case 'worklet': {
1495
+ let browsers = target.env.engines.browsers;
1496
+ engines = Array.isArray(browsers) ? browsers.join(', ') : browsers;
1497
+ break;
1498
+ }
1499
+ case 'node':
1500
+ engines = target.env.engines.node;
1501
+ break;
1502
+ case 'electron-main':
1503
+ case 'electron-renderer':
1504
+ engines = target.env.engines.electron;
1505
+ break;
1506
+ }
1507
+
1508
+ let highlights = [];
1509
+ if (input.loc) {
1510
+ highlights.push(
1511
+ convertSourceLocationToHighlight(input.loc, 'entry defined here'),
1512
+ );
1513
+ }
1514
+
1515
+ // Read package.json where target is defined.
1516
+ let targetFilePath = fromProjectPath(options.projectRoot, loc.filePath);
1517
+ let contents = await options.inputFS.readFile(targetFilePath, 'utf8');
1518
+
1519
+ // Builds up map of code highlights for each defined/inferred path in the package.json.
1520
+ let jsonHighlights = new Map();
1521
+ for (let key in info) {
1522
+ let keyInfo = info[key];
1523
+ let path = keyInfo.path || keyInfo.inferred;
1524
+ if (!path) {
1525
+ continue;
1526
+ }
1527
+
1528
+ let type = keyInfo.type || 'value';
1529
+ let highlight = jsonHighlights.get(path);
1530
+ if (!highlight) {
1531
+ highlight = {
1532
+ type: type,
1533
+ defined: '',
1534
+ inferred: [],
1535
+ };
1536
+ jsonHighlights.set(path, highlight);
1537
+ } else if (highlight.type !== type) {
1538
+ highlight.type = null;
1539
+ }
1540
+
1541
+ if (keyInfo.path) {
1542
+ highlight.defined = md`${key} defined here`;
1543
+ }
1544
+
1545
+ if (keyInfo.inferred) {
1546
+ highlight.inferred.push(
1547
+ md`${key} to be ${JSON.stringify(target.env[key])}`,
1548
+ );
1549
+ }
1550
+ }
1551
+
1552
+ // $FlowFixMe
1553
+ let listFormat = new Intl.ListFormat('en-US');
1554
+
1555
+ // Generate human friendly messages for each field.
1556
+ let highlightsWithMessages = [...jsonHighlights].map(([k, v]) => {
1557
+ let message = v.defined;
1558
+ if (v.inferred.length > 0) {
1559
+ message += (message ? ', ' : '') + 'caused ';
1560
+ message += listFormat.format(v.inferred);
1561
+ }
1562
+
1563
+ return {
1564
+ key: k,
1565
+ type: v.type,
1566
+ message,
1567
+ };
1568
+ });
1569
+
1570
+ // Get code highlights from JSON paths.
1571
+ highlights.push(
1572
+ ...generateJSONCodeHighlights(contents, highlightsWithMessages),
1573
+ );
1574
+
1575
+ // Format includeNodeModules to be human readable.
1576
+ let includeNodeModules;
1577
+ if (typeof target.env.includeNodeModules === 'boolean') {
1578
+ includeNodeModules = String(target.env.includeNodeModules);
1579
+ } else if (Array.isArray(target.env.includeNodeModules)) {
1580
+ includeNodeModules =
1581
+ 'only ' +
1582
+ listFormat.format(
1583
+ target.env.includeNodeModules.map(m => JSON.stringify(m)),
1584
+ );
1585
+ } else if (
1586
+ target.env.includeNodeModules &&
1587
+ typeof target.env.includeNodeModules === 'object'
1588
+ ) {
1589
+ includeNodeModules =
1590
+ 'all except ' +
1591
+ listFormat.format(
1592
+ Object.entries(target.env.includeNodeModules)
1593
+ .filter(([, v]) => v === false)
1594
+ .map(([k]) => JSON.stringify(k)),
1595
+ );
1596
+ }
1597
+
1598
+ let format = v => (v.message != null ? md.italic(v.message) : '');
1599
+ logger.verbose({
1600
+ origin: '@atlaspack/core',
1601
+ message: md`**Target** "${target.name}"
1602
+
1603
+ **Entry**: ${path.relative(
1604
+ process.cwd(),
1605
+ fromProjectPath(options.projectRoot, input.filePath),
1606
+ )}
1607
+ **Output**: ${path.relative(process.cwd(), output)}
1608
+ **Format**: ${target.env.outputFormat} ${format(
1609
+ info.outputFormat,
1610
+ )}
1611
+ **Context**: ${target.env.context} ${format(info.context)}
1612
+ **Engines**: ${engines || ''} ${format(info.engines)}
1613
+ **Library Mode**: ${String(target.env.isLibrary)} ${format(
1614
+ info.isLibrary,
1615
+ )}
1616
+ **Include Node Modules**: ${includeNodeModules} ${format(
1617
+ info.includeNodeModules,
1618
+ )}
1619
+ **Optimize**: ${String(target.env.shouldOptimize)} ${format(
1620
+ info.shouldOptimize,
1621
+ )}`,
1622
+ codeFrames: target.loc
1623
+ ? [
1624
+ {
1625
+ filePath: targetFilePath,
1626
+ codeHighlights: highlights,
1627
+ },
1628
+ ]
1629
+ : [],
1630
+ });
1631
+ }
1632
+ }