UNPKG

19.9 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _diagnostic = _interopRequireWildcard(require("@parcel/diagnostic"));
9
10var _utils = require("@parcel/utils");
11
12var _Environment = require("./Environment");
13
14var _path = _interopRequireDefault(require("path"));
15
16var _browserslist = _interopRequireDefault(require("browserslist"));
17
18var _jsonSourceMap = _interopRequireDefault(require("json-source-map"));
19
20var _assert = _interopRequireDefault(require("assert"));
21
22var _TargetDescriptor = require("./TargetDescriptor.schema");
23
24function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
25
26function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
27
28function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
29
30function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
31
32function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
33
34function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
35
36function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
37
38function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
39
40const DEFAULT_DEVELOPMENT_ENGINES = {
41 node: 'current',
42 browsers: ['last 1 Chrome version', 'last 1 Safari version', 'last 1 Firefox version', 'last 1 Edge version']
43};
44const DEFAULT_PRODUCTION_ENGINES = {
45 browsers: ['>= 0.25%'],
46 node: '8'
47};
48const DEFAULT_DIST_DIRNAME = 'dist';
49const COMMON_TARGETS = ['main', 'module', 'browser', 'types'];
50
51class TargetResolver {
52 constructor(options) {
53 _defineProperty(this, "fs", void 0);
54
55 _defineProperty(this, "options", void 0);
56
57 this.fs = options.inputFS;
58 this.options = options;
59 }
60
61 async resolve(rootDir = this.options.projectRoot) {
62 let optionTargets = this.options.targets;
63 let targets;
64 let files = [];
65
66 if (optionTargets) {
67 if (Array.isArray(optionTargets)) {
68 if (optionTargets.length === 0) {
69 throw new _diagnostic.default({
70 diagnostic: {
71 message: `Targets option is an empty array`,
72 origin: '@parcel/core'
73 }
74 });
75 } // If an array of strings is passed, it's a filter on the resolved package
76 // targets. Load them, and find the matching targets.
77
78
79 let packageTargets = await this.resolvePackageTargets(rootDir);
80 targets = optionTargets.map(target => {
81 let matchingTarget = packageTargets.targets.get(target);
82
83 if (!matchingTarget) {
84 throw new _diagnostic.default({
85 diagnostic: {
86 message: `Could not find target with name "${target}"`,
87 origin: '@parcel/core'
88 }
89 });
90 }
91
92 return matchingTarget;
93 });
94 files = packageTargets.files;
95 } else {
96 // Otherwise, it's an object map of target descriptors (similar to those
97 // in package.json). Adapt them to native targets.
98 targets = Object.entries(optionTargets).map(([name, _descriptor]) => {
99 let _parseDescriptor = parseDescriptor(name, _descriptor, null, {
100 targets: optionTargets
101 }),
102 {
103 distDir
104 } = _parseDescriptor,
105 descriptor = _objectWithoutProperties(_parseDescriptor, ["distDir"]);
106
107 if (!distDir) {
108 let optionTargetsString = JSON.stringify(optionTargets, null, '\t');
109 throw new _diagnostic.default({
110 diagnostic: {
111 message: `Missing distDir for target "${name}"`,
112 origin: '@parcel/core',
113 codeFrame: {
114 code: optionTargetsString,
115 codeHighlights: (0, _diagnostic.generateJSONCodeHighlights)(optionTargetsString, [{
116 key: `/${name}`,
117 type: 'value'
118 }])
119 }
120 }
121 });
122 }
123
124 return {
125 name,
126 distDir: _path.default.resolve(this.fs.cwd(), distDir),
127 publicUrl: descriptor.publicUrl,
128 env: (0, _Environment.createEnvironment)({
129 engines: descriptor.engines,
130 context: descriptor.context,
131 isLibrary: descriptor.isLibrary,
132 includeNodeModules: descriptor.includeNodeModules,
133 outputFormat: descriptor.outputFormat
134 }),
135 sourceMap: descriptor.sourceMap
136 };
137 });
138 }
139
140 if (this.options.serve) {
141 // In serve mode, we only support a single browser target. If the user
142 // provided more than one, or the matching target is not a browser, throw.
143 if (targets.length > 1) {
144 throw new _diagnostic.default({
145 diagnostic: {
146 message: `More than one target is not supported in serve mode`,
147 origin: '@parcel/core'
148 }
149 });
150 }
151
152 if (targets[0].env.context !== 'browser') {
153 throw new _diagnostic.default({
154 diagnostic: {
155 message: `Only browser targets are supported in serve mode`,
156 origin: '@parcel/core'
157 }
158 });
159 }
160 }
161 } else {
162 // Explicit targets were not provided. Either use a modern target for server
163 // mode, or simply use the package.json targets.
164 if (this.options.serve) {
165 var _serveOptions$publicU;
166
167 // In serve mode, we only support a single browser target. Since the user
168 // hasn't specified a target, use one targeting modern browsers for development
169 let serveOptions = this.options.serve;
170 targets = [{
171 name: 'default',
172 // For serve, write the `dist` to inside the parcel cache, which is
173 // temporary, likely in a .gitignore or similar, but still readily
174 // available for introspection by the user if necessary.
175 distDir: _path.default.resolve(this.options.cacheDir, DEFAULT_DIST_DIRNAME),
176 publicUrl: (_serveOptions$publicU = serveOptions.publicUrl) !== null && _serveOptions$publicU !== void 0 ? _serveOptions$publicU : '/',
177 env: (0, _Environment.createEnvironment)({
178 context: 'browser',
179 engines: {
180 browsers: DEFAULT_DEVELOPMENT_ENGINES.browsers
181 }
182 })
183 }];
184 } else {
185 let packageTargets = await this.resolvePackageTargets(rootDir);
186 targets = Array.from(packageTargets.targets.values());
187 files = packageTargets.files;
188 }
189 }
190
191 return {
192 targets,
193 files
194 };
195 }
196
197 async resolvePackageTargets(rootDir) {
198 var _this$options$default;
199
200 let conf = await (0, _utils.loadConfig)(this.fs, _path.default.join(rootDir, 'index'), ['package.json']);
201 let pkg;
202 let pkgContents;
203 let pkgFilePath;
204 let pkgDir;
205 let pkgMap;
206
207 if (conf) {
208 pkg = conf.config;
209 let pkgFile = conf.files[0];
210
211 if (pkgFile == null) {
212 throw new _diagnostic.default({
213 diagnostic: {
214 message: `Expected package.json file in ${rootDir}`,
215 origin: '@parcel/core'
216 }
217 });
218 }
219
220 pkgFilePath = pkgFile.filePath;
221 pkgDir = _path.default.dirname(pkgFilePath);
222 pkgContents = await this.fs.readFile(pkgFilePath, 'utf8');
223 pkgMap = _jsonSourceMap.default.parse(pkgContents.replace(/\t/g, ' '));
224 } else {
225 pkg = {};
226 pkgDir = this.fs.cwd();
227 }
228
229 let pkgTargets = pkg.targets || {};
230 let pkgEngines = parseEngines(pkg.engines, pkgFilePath, pkgContents, '/engines', 'Invalid engines in package.json') || {};
231
232 if (!pkgEngines.browsers) {
233 let browserslistBrowsers = _browserslist.default.loadConfig({
234 path: rootDir
235 });
236
237 if (browserslistBrowsers) {
238 pkgEngines.browsers = browserslistBrowsers;
239 }
240 }
241
242 let targets = new Map();
243 let node = pkgEngines.node;
244 let browsers = pkgEngines.browsers; // If there is a separate `browser` target, or an `engines.node` field but no browser targets, then
245 // the `main` and `module` targets refer to node, otherwise browser.
246
247 let mainContext = pkg.browser || pkgTargets.browser || node && !browsers ? 'node' : 'browser';
248 let moduleContext = pkg.browser || pkgTargets.browser ? 'browser' : mainContext;
249 let defaultEngines = (_this$options$default = this.options.defaultEngines) !== null && _this$options$default !== void 0 ? _this$options$default : this.options.mode === 'production' ? DEFAULT_PRODUCTION_ENGINES : DEFAULT_DEVELOPMENT_ENGINES;
250 let context = browsers || !node ? 'browser' : 'node';
251
252 if (context === 'browser' && pkgEngines.browsers == null) {
253 pkgEngines.browsers = defaultEngines.browsers;
254 } else if (context === 'node' && pkgEngines.node == null) {
255 pkgEngines.node = defaultEngines.node;
256 }
257
258 for (let targetName of COMMON_TARGETS) {
259 let targetDist;
260 let pointer;
261
262 if (targetName === 'browser' && pkg[targetName] != null && typeof pkg[targetName] === 'object') {
263 // The `browser` field can be a file path or an alias map.
264 targetDist = pkg[targetName][pkg.name];
265 pointer = `/${targetName}/${pkg.name}`;
266 } else {
267 targetDist = pkg[targetName];
268 pointer = `/${targetName}`;
269 }
270
271 if (typeof targetDist === 'string' || pkgTargets[targetName]) {
272 var _pkgTargets$targetNam, _descriptor$publicUrl, _descriptor$engines, _descriptor$context, _descriptor$includeNo, _descriptor$outputFor;
273
274 let distDir;
275 let distEntry;
276 let loc;
277 (0, _assert.default)(typeof pkgFilePath === 'string');
278 (0, _assert.default)(pkgMap != null);
279
280 let _descriptor = (_pkgTargets$targetNam = pkgTargets[targetName]) !== null && _pkgTargets$targetNam !== void 0 ? _pkgTargets$targetNam : {};
281
282 if (typeof targetDist === 'string') {
283 distDir = _path.default.resolve(pkgDir, _path.default.dirname(targetDist));
284 distEntry = _path.default.basename(targetDist);
285 loc = _objectSpread({
286 filePath: pkgFilePath
287 }, (0, _diagnostic.getJSONSourceLocation)(pkgMap.pointers[pointer], 'value'));
288 } else {
289 distDir = _path.default.resolve(pkgDir, DEFAULT_DIST_DIRNAME, targetName);
290 }
291
292 let descriptor = parseCommonTargetDescriptor(targetName, _descriptor, pkgFilePath, pkgContents);
293 if (!descriptor) continue;
294 let isLibrary = typeof distEntry === 'string' ? _path.default.extname(distEntry) === '.js' : false;
295 targets.set(targetName, {
296 name: targetName,
297 distDir,
298 distEntry,
299 publicUrl: (_descriptor$publicUrl = descriptor.publicUrl) !== null && _descriptor$publicUrl !== void 0 ? _descriptor$publicUrl : '/',
300 env: (0, _Environment.createEnvironment)({
301 engines: (_descriptor$engines = descriptor.engines) !== null && _descriptor$engines !== void 0 ? _descriptor$engines : pkgEngines,
302 context: (_descriptor$context = descriptor.context) !== null && _descriptor$context !== void 0 ? _descriptor$context : targetName === 'browser' ? 'browser' : targetName === 'module' ? moduleContext : mainContext,
303 includeNodeModules: (_descriptor$includeNo = descriptor.includeNodeModules) !== null && _descriptor$includeNo !== void 0 ? _descriptor$includeNo : !isLibrary,
304 outputFormat: (_descriptor$outputFor = descriptor.outputFormat) !== null && _descriptor$outputFor !== void 0 ? _descriptor$outputFor : isLibrary ? targetName === 'module' ? 'esmodule' : 'commonjs' : 'global',
305 isLibrary: isLibrary
306 }),
307 sourceMap: descriptor.sourceMap,
308 loc
309 });
310 }
311 } // Custom targets
312
313
314 for (let targetName in pkgTargets) {
315 if (COMMON_TARGETS.includes(targetName)) {
316 continue;
317 }
318
319 let distPath = pkg[targetName];
320 let distDir;
321 let distEntry;
322 let loc;
323
324 if (distPath == null) {
325 distDir = _path.default.resolve(pkgDir, DEFAULT_DIST_DIRNAME, targetName);
326 } else {
327 if (typeof distPath !== 'string') {
328 let contents = typeof pkgContents === 'string' ? pkgContents : // $FlowFixMe
329 JSON.stringify(pkgContents, null, '\t');
330 throw new _diagnostic.default({
331 diagnostic: {
332 message: `Invalid distPath for target "${targetName}"`,
333 origin: '@parcel/core',
334 language: 'json',
335 filePath: pkgFilePath || undefined,
336 codeFrame: {
337 code: contents,
338 codeHighlights: (0, _diagnostic.generateJSONCodeHighlights)(contents, [{
339 key: `/${targetName}`,
340 type: 'value',
341 message: 'Expected type string'
342 }])
343 }
344 }
345 });
346 }
347
348 distDir = _path.default.resolve(pkgDir, _path.default.dirname(distPath));
349 distEntry = _path.default.basename(distPath);
350 (0, _assert.default)(typeof pkgFilePath === 'string');
351 (0, _assert.default)(pkgMap != null);
352 loc = _objectSpread({
353 filePath: pkgFilePath
354 }, (0, _diagnostic.getJSONSourceLocation)(pkgMap.pointers[`/${targetName}`], 'value'));
355 }
356
357 if (targetName in pkgTargets) {
358 var _descriptor$publicUrl2, _descriptor$engines2;
359
360 let descriptor = parseDescriptor(targetName, pkgTargets[targetName], pkgFilePath, pkgContents);
361 targets.set(targetName, {
362 name: targetName,
363 distDir,
364 distEntry,
365 publicUrl: (_descriptor$publicUrl2 = descriptor.publicUrl) !== null && _descriptor$publicUrl2 !== void 0 ? _descriptor$publicUrl2 : '/',
366 env: (0, _Environment.createEnvironment)({
367 engines: (_descriptor$engines2 = descriptor.engines) !== null && _descriptor$engines2 !== void 0 ? _descriptor$engines2 : pkgEngines,
368 context: descriptor.context,
369 includeNodeModules: descriptor.includeNodeModules,
370 outputFormat: descriptor.outputFormat,
371 isLibrary: descriptor.isLibrary
372 }),
373 sourceMap: descriptor.sourceMap,
374 loc
375 });
376 }
377 } // If no explicit targets were defined, add a default.
378
379
380 if (targets.size === 0) {
381 targets.set('default', {
382 name: 'default',
383 distDir: _path.default.resolve(this.fs.cwd(), DEFAULT_DIST_DIRNAME),
384 publicUrl: '/',
385 env: (0, _Environment.createEnvironment)({
386 engines: pkgEngines,
387 context
388 })
389 });
390 }
391
392 assertNoDuplicateTargets(targets, pkgFilePath, pkgContents);
393 return {
394 targets,
395 files: conf ? conf.files : []
396 };
397 }
398
399}
400
401exports.default = TargetResolver;
402
403function parseEngines(engines, pkgPath, pkgContents, prependKey, message) {
404 if (engines === undefined) {
405 return engines;
406 } else {
407 _utils.validateSchema.diagnostic(_TargetDescriptor.ENGINES_SCHEMA, engines, pkgPath, pkgContents, '@parcel/core', prependKey, message); // $FlowFixMe we just verified this
408
409
410 return engines;
411 }
412}
413
414function parseDescriptor(targetName, descriptor, pkgPath, pkgContents) {
415 _utils.validateSchema.diagnostic(_TargetDescriptor.DESCRIPTOR_SCHEMA, descriptor, pkgPath, pkgContents, '@parcel/core', `/targets/${targetName}`, `Invalid target descriptor for target "${targetName}"`); // $FlowFixMe we just verified this
416
417
418 return descriptor;
419}
420
421function parseCommonTargetDescriptor(targetName, descriptor, pkgPath, pkgContents) {
422 _utils.validateSchema.diagnostic(_TargetDescriptor.COMMON_TARGET_DESCRIPTOR_SCHEMA, descriptor, pkgPath, pkgContents, '@parcel/core', `/targets/${targetName}`, `Invalid target descriptor for target "${targetName}"`); // $FlowFixMe we just verified this
423
424
425 return descriptor;
426}
427
428function assertNoDuplicateTargets(targets, pkgFilePath, pkgContents) {
429 // Detect duplicate targets by destination path and provide a nice error.
430 // Without this, an assertion is thrown much later after naming the bundles and finding duplicates.
431 let targetsByPath = new Map();
432
433 for (let target of targets.values()) {
434 if (target.distEntry) {
435 var _targetsByPath$get;
436
437 let distPath = _path.default.join(target.distDir, target.distEntry);
438
439 if (!targetsByPath.has(distPath)) {
440 targetsByPath.set(distPath, []);
441 }
442
443 (_targetsByPath$get = targetsByPath.get(distPath)) === null || _targetsByPath$get === void 0 ? void 0 : _targetsByPath$get.push(target.name);
444 }
445 }
446
447 let diagnostics = [];
448
449 for (let [targetPath, targetNames] of targetsByPath) {
450 if (targetNames.length > 1 && pkgContents && pkgFilePath) {
451 diagnostics.push({
452 message: `Multiple targets have the same destination path "${_path.default.relative(_path.default.dirname(pkgFilePath), targetPath)}"`,
453 origin: '@parcel/core',
454 language: 'json',
455 filePath: pkgFilePath || undefined,
456 codeFrame: {
457 code: pkgContents,
458 codeHighlights: (0, _diagnostic.generateJSONCodeHighlights)(pkgContents, targetNames.map(t => ({
459 key: `/${t}`,
460 type: 'value'
461 })))
462 }
463 });
464 }
465 }
466
467 if (diagnostics.length > 0) {
468 // Only add hints to the last diagnostic so it isn't duplicated on each one
469 diagnostics[diagnostics.length - 1].hints = ['Try removing the duplicate targets, or changing the destination paths.'];
470 throw new _diagnostic.default({
471 diagnostic: diagnostics
472 });
473 }
474}
\No newline at end of file