UNPKG

14.2 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
6
7const _require = require('path'),
8 relative = _require.relative;
9
10const template = require('@babel/template').default;
11
12const t = require('@babel/types');
13
14const traverse = require('@babel/traverse').default;
15
16const generate = require('@babel/generator').default;
17
18const treeShake = require('./shake');
19
20const mangleScope = require('./mangler');
21
22const _require2 = require('./utils'),
23 getName = _require2.getName,
24 getIdentifier = _require2.getIdentifier;
25
26const EXPORTS_RE = /^\$([^$]+)\$exports$/;
27const DEFAULT_INTEROP_TEMPLATE = template('var NAME = $parcel$interopDefault(MODULE)');
28const THROW_TEMPLATE = template('$parcel$missingModule(MODULE)');
29const REQUIRE_TEMPLATE = template('require(ID)');
30
31module.exports = (packager, ast) => {
32 let assets = packager.assets;
33 let replacements = new Map();
34 let imports = new Map();
35 let referenced = new Set(); // Build a mapping of all imported identifiers to replace.
36
37 var _iteratorNormalCompletion = true;
38 var _didIteratorError = false;
39 var _iteratorError = undefined;
40
41 try {
42 for (var _iterator = assets.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
43 let asset = _step.value;
44
45 for (let name in asset.cacheData.imports) {
46 let imp = asset.cacheData.imports[name];
47 imports.set(name, [packager.resolveModule(asset.id, imp[0]), imp[1]]);
48 }
49 }
50 } catch (err) {
51 _didIteratorError = true;
52 _iteratorError = err;
53 } finally {
54 try {
55 if (!_iteratorNormalCompletion && _iterator.return != null) {
56 _iterator.return();
57 }
58 } finally {
59 if (_didIteratorError) {
60 throw _iteratorError;
61 }
62 }
63 }
64
65 function replaceExportNode(module, originalName, path) {
66 let _packager$findExportM = packager.findExportModule(module.id, originalName, replacements),
67 identifier = _packager$findExportM.identifier,
68 name = _packager$findExportM.name,
69 id = _packager$findExportM.id;
70
71 let mod = assets.get(id);
72 let node;
73
74 if (identifier) {
75 node = findSymbol(path, identifier);
76 } // If the module is not in this bundle, create a `require` call for it.
77
78
79 if (!node && !mod) {
80 node = REQUIRE_TEMPLATE({
81 ID: t.stringLiteral(id)
82 }).expression;
83 return interop(module, name, path, node);
84 } // If this is an ES6 module, throw an error if we cannot resolve the module
85
86
87 if (!node && !mod.cacheData.isCommonJS && mod.cacheData.isES6Module) {
88 let relativePath = relative(packager.options.rootDir, mod.name);
89 throw new Error(`${relativePath} does not export '${name}'`);
90 } // If it is CommonJS, look for an exports object.
91
92
93 if (!node && mod.cacheData.isCommonJS) {
94 node = findSymbol(path, getName(mod, 'exports'));
95
96 if (!node) {
97 return null;
98 }
99
100 return interop(mod, name, path, node);
101 }
102
103 return node;
104 }
105
106 function findSymbol(path, symbol) {
107 if (replacements.has(symbol)) {
108 symbol = replacements.get(symbol);
109 } // if the symbol is in the scope there is not need to remap it
110
111
112 if (path.scope.getProgramParent().hasBinding(symbol)) {
113 return t.identifier(symbol);
114 }
115
116 return null;
117 }
118
119 function interop(mod, originalName, path, node) {
120 // Handle interop for default imports of CommonJS modules.
121 if (mod.cacheData.isCommonJS && originalName === 'default') {
122 let name = getName(mod, '$interop$default');
123
124 if (!path.scope.getBinding(name)) {
125 let _path$getStatementPar = path.getStatementParent().insertBefore(DEFAULT_INTEROP_TEMPLATE({
126 NAME: t.identifier(name),
127 MODULE: node
128 })),
129 _path$getStatementPar2 = (0, _slicedToArray2.default)(_path$getStatementPar, 1),
130 decl = _path$getStatementPar2[0];
131
132 let binding = path.scope.getBinding(getName(mod, 'exports'));
133
134 if (binding) {
135 binding.reference(decl.get('declarations.0.init'));
136 }
137
138 path.scope.registerDeclaration(decl);
139 }
140
141 return t.memberExpression(t.identifier(name), t.identifier('d'));
142 } // if there is a CommonJS export return $id$exports.name
143
144
145 if (originalName !== '*') {
146 return t.memberExpression(node, t.identifier(originalName));
147 }
148
149 return node;
150 }
151
152 function isUnusedValue(path) {
153 return path.parentPath.isExpressionStatement() || path.parentPath.isSequenceExpression() && (path.key !== path.container.length - 1 || isUnusedValue(path.parentPath));
154 }
155
156 traverse(ast, {
157 CallExpression(path) {
158 let _path$node = path.node,
159 args = _path$node.arguments,
160 callee = _path$node.callee;
161
162 if (!t.isIdentifier(callee)) {
163 return;
164 } // each require('module') call gets replaced with $parcel$require(id, 'module')
165
166
167 if (callee.name === '$parcel$require') {
168 let _args = (0, _slicedToArray2.default)(args, 2),
169 id = _args[0],
170 source = _args[1];
171
172 if (args.length !== 2 || !t.isStringLiteral(id) || !t.isStringLiteral(source)) {
173 throw new Error('invariant: invalid signature, expected : $parcel$require(number, string)');
174 }
175
176 let mod = packager.resolveModule(id.value, source.value);
177
178 if (!mod) {
179 if (assets.get(id.value).dependencies.get(source.value).optional) {
180 path.replaceWith(THROW_TEMPLATE({
181 MODULE: t.stringLiteral(source.value)
182 }));
183 } else {
184 throw new Error(`Cannot find module "${source.value}" in asset ${id.value}`);
185 }
186 } else {
187 let node;
188
189 if (assets.get(mod.id)) {
190 // Replace with nothing if the require call's result is not used.
191 if (!isUnusedValue(path)) {
192 let name = getName(mod, 'exports');
193 node = t.identifier(replacements.get(name) || name);
194 } // We need to wrap the module in a function when a require
195 // call happens inside a non top-level scope, e.g. in a
196 // function, if statement, or conditional expression.
197
198
199 if (mod.cacheData.shouldWrap) {
200 let call = t.callExpression(getIdentifier(mod, 'init'), []);
201 node = node ? t.sequenceExpression([call, node]) : call;
202 }
203 } else {
204 node = REQUIRE_TEMPLATE({
205 ID: t.stringLiteral(mod.id)
206 }).expression;
207 }
208
209 if (node) {
210 path.replaceWith(node);
211 } else {
212 path.remove();
213 }
214 }
215 } else if (callee.name === '$parcel$require$resolve') {
216 let _args2 = (0, _slicedToArray2.default)(args, 2),
217 id = _args2[0],
218 source = _args2[1];
219
220 if (args.length !== 2 || !t.isStringLiteral(id) || !t.isStringLiteral(source)) {
221 throw new Error('invariant: invalid signature, expected : $parcel$require$resolve(number, string)');
222 }
223
224 let mapped = assets.get(id.value);
225 let dep = mapped.dependencies.get(source.value);
226 let mod = mapped.depAssets.get(dep);
227 let bundles = mod.id;
228
229 if (dep.dynamic && packager.bundle.childBundles.has(mod.parentBundle)) {
230 bundles = [];
231 var _iteratorNormalCompletion2 = true;
232 var _didIteratorError2 = false;
233 var _iteratorError2 = undefined;
234
235 try {
236 for (var _iterator2 = mod.parentBundle.siblingBundles[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
237 let child = _step2.value;
238
239 if (!child.isEmpty && packager.options.bundleLoaders[child.type]) {
240 bundles.push(packager.getBundleSpecifier(child));
241 }
242 }
243 } catch (err) {
244 _didIteratorError2 = true;
245 _iteratorError2 = err;
246 } finally {
247 try {
248 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
249 _iterator2.return();
250 }
251 } finally {
252 if (_didIteratorError2) {
253 throw _iteratorError2;
254 }
255 }
256 }
257
258 bundles.push(packager.getBundleSpecifier(mod.parentBundle));
259 bundles.push(mod.id);
260 }
261
262 path.replaceWith(t.valueToNode(bundles));
263 }
264 },
265
266 VariableDeclarator: {
267 exit(path) {
268 // Replace references to declarations like `var x = require('x')`
269 // with the final export identifier instead.
270 // This allows us to potentially replace accesses to e.g. `x.foo` with
271 // a variable like `$id$export$foo` later, avoiding the exports object altogether.
272 let _path$node2 = path.node,
273 id = _path$node2.id,
274 init = _path$node2.init;
275
276 if (!t.isIdentifier(init)) {
277 return;
278 }
279
280 let match = init.name.match(EXPORTS_RE);
281
282 if (!match) {
283 return;
284 } // Replace patterns like `var {x} = require('y')` with e.g. `$id$export$x`.
285
286
287 if (t.isObjectPattern(id)) {
288 var _iteratorNormalCompletion3 = true;
289 var _didIteratorError3 = false;
290 var _iteratorError3 = undefined;
291
292 try {
293 for (var _iterator3 = path.get('id.properties')[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
294 let p = _step3.value;
295 let _p$node = p.node,
296 computed = _p$node.computed,
297 key = _p$node.key,
298 value = _p$node.value;
299
300 if (computed || !t.isIdentifier(key) || !t.isIdentifier(value)) {
301 continue;
302 }
303
304 let _packager$findExportM2 = packager.findExportModule(match[1], key.name, replacements),
305 identifier = _packager$findExportM2.identifier;
306
307 if (identifier) {
308 replace(value.name, identifier, p);
309 }
310 }
311 } catch (err) {
312 _didIteratorError3 = true;
313 _iteratorError3 = err;
314 } finally {
315 try {
316 if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
317 _iterator3.return();
318 }
319 } finally {
320 if (_didIteratorError3) {
321 throw _iteratorError3;
322 }
323 }
324 }
325
326 if (id.properties.length === 0) {
327 path.remove();
328 }
329 } else if (t.isIdentifier(id)) {
330 replace(id.name, init.name, path);
331 }
332
333 function replace(id, init, path) {
334 let binding = path.scope.getBinding(id);
335
336 if (!binding.constant) {
337 return;
338 }
339
340 var _iteratorNormalCompletion4 = true;
341 var _didIteratorError4 = false;
342 var _iteratorError4 = undefined;
343
344 try {
345 for (var _iterator4 = binding.referencePaths[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
346 let ref = _step4.value;
347 ref.replaceWith(t.identifier(init));
348 }
349 } catch (err) {
350 _didIteratorError4 = true;
351 _iteratorError4 = err;
352 } finally {
353 try {
354 if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
355 _iterator4.return();
356 }
357 } finally {
358 if (_didIteratorError4) {
359 throw _iteratorError4;
360 }
361 }
362 }
363
364 replacements.set(id, init);
365 path.remove();
366 }
367 }
368
369 },
370 MemberExpression: {
371 exit(path) {
372 if (!path.isReferenced()) {
373 return;
374 }
375
376 let _path$node3 = path.node,
377 object = _path$node3.object,
378 property = _path$node3.property,
379 computed = _path$node3.computed;
380
381 if (!(t.isIdentifier(object) && (t.isIdentifier(property) && !computed || t.isStringLiteral(property)))) {
382 return;
383 }
384
385 let match = object.name.match(EXPORTS_RE); // If it's a $id$exports.name expression.
386
387 if (match) {
388 let name = t.isIdentifier(property) ? property.name : property.value;
389
390 let _packager$findExportM3 = packager.findExportModule(match[1], name, replacements),
391 identifier = _packager$findExportM3.identifier; // Check if $id$export$name exists and if so, replace the node by it.
392
393
394 if (identifier) {
395 path.replaceWith(t.identifier(identifier));
396 }
397 }
398 }
399
400 },
401
402 ReferencedIdentifier(path) {
403 let name = path.node.name;
404
405 if (typeof name !== 'string') {
406 return;
407 }
408
409 if (imports.has(name)) {
410 let imp = imports.get(name);
411 let node = replaceExportNode(imp[0], imp[1], path); // If the export does not exist, replace with an empty object.
412
413 if (!node) {
414 node = t.objectExpression([]);
415 }
416
417 path.replaceWith(node);
418 return;
419 }
420
421 let match = name.match(EXPORTS_RE);
422
423 if (match) {
424 referenced.add(name);
425 } // If it's an undefined $id$exports identifier.
426
427
428 if (match && !path.scope.hasBinding(name)) {
429 path.replaceWith(t.objectExpression([]));
430 }
431 },
432
433 Program: {
434 // A small optimization to remove unused CommonJS exports as sometimes Uglify doesn't remove them.
435 exit(path) {
436 treeShake(path.scope);
437
438 if (packager.options.minify) {
439 mangleScope(path.scope);
440 }
441 }
442
443 }
444 });
445 let opts = {
446 sourceMaps: packager.options.sourceMaps,
447 sourceFileName: packager.bundle.name,
448 minified: packager.options.minify,
449 comments: !packager.options.minify
450 };
451 return generate(ast, opts);
452};
\No newline at end of file