@parcel/packager-js 2.0.0-nightly.97 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/CJSOutputFormat.js +45 -0
- package/lib/DevPackager.js +230 -0
- package/lib/ESMOutputFormat.js +117 -0
- package/lib/GlobalOutputFormat.js +24 -0
- package/lib/ScopeHoistingPackager.js +1001 -0
- package/lib/{prelude.js → dev-prelude.js} +23 -12
- package/lib/helpers.js +81 -0
- package/lib/index.js +149 -0
- package/lib/utils.js +62 -0
- package/package.json +17 -10
- package/src/.eslintrc.json +13 -0
- package/src/CJSOutputFormat.js +42 -0
- package/src/DevPackager.js +232 -0
- package/src/ESMOutputFormat.js +111 -0
- package/src/GlobalOutputFormat.js +24 -0
- package/src/ScopeHoistingPackager.js +1172 -0
- package/src/{prelude.js → dev-prelude.js} +23 -12
- package/src/helpers.js +75 -0
- package/src/index.js +102 -0
- package/src/utils.js +57 -0
- package/lib/JSPackager.js +0 -174
- package/src/JSPackager.js +0 -190
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
import type {BundleGraph, PluginOptions, NamedBundle} from '@parcel/types';
|
|
3
|
+
|
|
4
|
+
import {PromiseQueue, relativeBundlePath, countLines} from '@parcel/utils';
|
|
5
|
+
import SourceMap from '@parcel/source-map';
|
|
6
|
+
import invariant from 'assert';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import {replaceScriptDependencies, getSpecifier} from './utils';
|
|
10
|
+
|
|
11
|
+
const PRELUDE = fs
|
|
12
|
+
.readFileSync(path.join(__dirname, 'dev-prelude.js'), 'utf8')
|
|
13
|
+
.trim()
|
|
14
|
+
.replace(/;$/, '');
|
|
15
|
+
|
|
16
|
+
export class DevPackager {
|
|
17
|
+
options: PluginOptions;
|
|
18
|
+
bundleGraph: BundleGraph<NamedBundle>;
|
|
19
|
+
bundle: NamedBundle;
|
|
20
|
+
parcelRequireName: string;
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
options: PluginOptions,
|
|
24
|
+
bundleGraph: BundleGraph<NamedBundle>,
|
|
25
|
+
bundle: NamedBundle,
|
|
26
|
+
parcelRequireName: string,
|
|
27
|
+
) {
|
|
28
|
+
this.options = options;
|
|
29
|
+
this.bundleGraph = bundleGraph;
|
|
30
|
+
this.bundle = bundle;
|
|
31
|
+
this.parcelRequireName = parcelRequireName;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async package(): Promise<{|contents: string, map: ?SourceMap|}> {
|
|
35
|
+
// Load assets
|
|
36
|
+
let queue = new PromiseQueue({maxConcurrent: 32});
|
|
37
|
+
this.bundle.traverse(node => {
|
|
38
|
+
if (node.type === 'asset') {
|
|
39
|
+
queue.add(async () => {
|
|
40
|
+
let [code, mapBuffer] = await Promise.all([
|
|
41
|
+
node.value.getCode(),
|
|
42
|
+
this.bundle.env.sourceMap && node.value.getMapBuffer(),
|
|
43
|
+
]);
|
|
44
|
+
return {code, mapBuffer};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
let results = await queue.run();
|
|
50
|
+
|
|
51
|
+
let assets = '';
|
|
52
|
+
let i = 0;
|
|
53
|
+
let first = true;
|
|
54
|
+
let map = new SourceMap(this.options.projectRoot);
|
|
55
|
+
|
|
56
|
+
let prefix = this.getPrefix();
|
|
57
|
+
let lineOffset = countLines(prefix);
|
|
58
|
+
let script: ?{|code: string, mapBuffer: ?Buffer|} = null;
|
|
59
|
+
|
|
60
|
+
this.bundle.traverse(node => {
|
|
61
|
+
let wrapped = first ? '' : ',';
|
|
62
|
+
|
|
63
|
+
if (node.type === 'dependency') {
|
|
64
|
+
let resolved = this.bundleGraph.getResolvedAsset(
|
|
65
|
+
node.value,
|
|
66
|
+
this.bundle,
|
|
67
|
+
);
|
|
68
|
+
if (resolved && resolved.type !== 'js') {
|
|
69
|
+
// if this is a reference to another javascript asset, we should not include
|
|
70
|
+
// its output, as its contents should already be loaded.
|
|
71
|
+
invariant(!this.bundle.hasAsset(resolved));
|
|
72
|
+
wrapped +=
|
|
73
|
+
JSON.stringify(this.bundleGraph.getAssetPublicId(resolved)) +
|
|
74
|
+
':[function() {},{}]';
|
|
75
|
+
} else {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (node.type === 'asset') {
|
|
81
|
+
let asset = node.value;
|
|
82
|
+
invariant(
|
|
83
|
+
asset.type === 'js',
|
|
84
|
+
'all assets in a js bundle must be js assets',
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// If this is the main entry of a script rather than a module, we need to hoist it
|
|
88
|
+
// outside the bundle wrapper function so that its variables are exposed as globals.
|
|
89
|
+
if (
|
|
90
|
+
this.bundle.env.sourceType === 'script' &&
|
|
91
|
+
asset === this.bundle.getMainEntry()
|
|
92
|
+
) {
|
|
93
|
+
script = results[i++];
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let deps = {};
|
|
98
|
+
let dependencies = this.bundleGraph.getDependencies(asset);
|
|
99
|
+
for (let dep of dependencies) {
|
|
100
|
+
let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
|
|
101
|
+
if (this.bundleGraph.isDependencySkipped(dep)) {
|
|
102
|
+
deps[getSpecifier(dep)] = false;
|
|
103
|
+
} else if (resolved) {
|
|
104
|
+
deps[getSpecifier(dep)] =
|
|
105
|
+
this.bundleGraph.getAssetPublicId(resolved);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let {code, mapBuffer} = results[i];
|
|
110
|
+
let output = code || '';
|
|
111
|
+
wrapped +=
|
|
112
|
+
JSON.stringify(this.bundleGraph.getAssetPublicId(asset)) +
|
|
113
|
+
':[function(require,module,exports) {\n' +
|
|
114
|
+
output +
|
|
115
|
+
'\n},';
|
|
116
|
+
wrapped += JSON.stringify(deps);
|
|
117
|
+
wrapped += ']';
|
|
118
|
+
|
|
119
|
+
if (this.bundle.env.sourceMap) {
|
|
120
|
+
if (mapBuffer) {
|
|
121
|
+
map.addBuffer(mapBuffer, lineOffset);
|
|
122
|
+
} else {
|
|
123
|
+
map.addEmptyMap(
|
|
124
|
+
path
|
|
125
|
+
.relative(this.options.projectRoot, asset.filePath)
|
|
126
|
+
.replace(/\\+/g, '/'),
|
|
127
|
+
output,
|
|
128
|
+
lineOffset,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
lineOffset += countLines(output) + 1;
|
|
133
|
+
}
|
|
134
|
+
i++;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
assets += wrapped;
|
|
138
|
+
first = false;
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
let entries = this.bundle.getEntryAssets();
|
|
142
|
+
let mainEntry = this.bundle.getMainEntry();
|
|
143
|
+
if (
|
|
144
|
+
(!this.isEntry() && this.bundle.env.outputFormat === 'global') ||
|
|
145
|
+
this.bundle.env.sourceType === 'script'
|
|
146
|
+
) {
|
|
147
|
+
// In async bundles we don't want the main entry to execute until we require it
|
|
148
|
+
// as there might be dependencies in a sibling bundle that hasn't loaded yet.
|
|
149
|
+
entries = entries.filter(a => a.id !== mainEntry?.id);
|
|
150
|
+
mainEntry = null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let contents =
|
|
154
|
+
prefix +
|
|
155
|
+
'({' +
|
|
156
|
+
assets +
|
|
157
|
+
'},' +
|
|
158
|
+
JSON.stringify(
|
|
159
|
+
entries.map(asset => this.bundleGraph.getAssetPublicId(asset)),
|
|
160
|
+
) +
|
|
161
|
+
', ' +
|
|
162
|
+
JSON.stringify(
|
|
163
|
+
mainEntry ? this.bundleGraph.getAssetPublicId(mainEntry) : null,
|
|
164
|
+
) +
|
|
165
|
+
', ' +
|
|
166
|
+
JSON.stringify(this.parcelRequireName) +
|
|
167
|
+
')' +
|
|
168
|
+
'\n';
|
|
169
|
+
|
|
170
|
+
// The entry asset of a script bundle gets hoisted outside the bundle wrapper function
|
|
171
|
+
// so that its variables become globals. We need to replace any require calls for
|
|
172
|
+
// runtimes with a parcelRequire call.
|
|
173
|
+
if (this.bundle.env.sourceType === 'script' && script) {
|
|
174
|
+
let entryMap;
|
|
175
|
+
let mapBuffer = script.mapBuffer;
|
|
176
|
+
if (mapBuffer) {
|
|
177
|
+
entryMap = new SourceMap(this.options.projectRoot, mapBuffer);
|
|
178
|
+
}
|
|
179
|
+
contents += replaceScriptDependencies(
|
|
180
|
+
this.bundleGraph,
|
|
181
|
+
this.bundle,
|
|
182
|
+
script.code,
|
|
183
|
+
entryMap,
|
|
184
|
+
this.parcelRequireName,
|
|
185
|
+
);
|
|
186
|
+
if (this.bundle.env.sourceMap && entryMap) {
|
|
187
|
+
map.addSourceMap(entryMap, lineOffset);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
contents,
|
|
193
|
+
map,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
getPrefix(): string {
|
|
198
|
+
let interpreter: ?string;
|
|
199
|
+
let mainEntry = this.bundle.getMainEntry();
|
|
200
|
+
if (mainEntry && this.isEntry() && !this.bundle.target.env.isBrowser()) {
|
|
201
|
+
let _interpreter = mainEntry.meta.interpreter;
|
|
202
|
+
invariant(_interpreter == null || typeof _interpreter === 'string');
|
|
203
|
+
interpreter = _interpreter;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
let importScripts = '';
|
|
207
|
+
if (this.bundle.env.isWorker()) {
|
|
208
|
+
let bundles = this.bundleGraph.getReferencedBundles(this.bundle);
|
|
209
|
+
for (let b of bundles) {
|
|
210
|
+
importScripts += `importScripts("${relativeBundlePath(
|
|
211
|
+
this.bundle,
|
|
212
|
+
b,
|
|
213
|
+
)}");\n`;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
// If the entry asset included a hashbang, repeat it at the top of the bundle
|
|
219
|
+
(interpreter != null ? `#!${interpreter}\n` : '') +
|
|
220
|
+
importScripts +
|
|
221
|
+
PRELUDE
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
isEntry(): boolean {
|
|
226
|
+
return (
|
|
227
|
+
!this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') ||
|
|
228
|
+
this.bundle.env.isIsolated() ||
|
|
229
|
+
this.bundle.bundleBehavior === 'isolated'
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type {
|
|
3
|
+
ScopeHoistingPackager,
|
|
4
|
+
OutputFormat,
|
|
5
|
+
} from './ScopeHoistingPackager';
|
|
6
|
+
|
|
7
|
+
export class ESMOutputFormat implements OutputFormat {
|
|
8
|
+
packager: ScopeHoistingPackager;
|
|
9
|
+
|
|
10
|
+
constructor(packager: ScopeHoistingPackager) {
|
|
11
|
+
this.packager = packager;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
buildBundlePrelude(): [string, number] {
|
|
15
|
+
let res = '';
|
|
16
|
+
let lines = 0;
|
|
17
|
+
for (let [source, specifiers] of this.packager.externals) {
|
|
18
|
+
let defaultSpecifier = null;
|
|
19
|
+
let namespaceSpecifier = null;
|
|
20
|
+
let namedSpecifiers = [];
|
|
21
|
+
for (let [imported, symbol] of specifiers) {
|
|
22
|
+
if (imported === 'default' /* || isCommonJS*/) {
|
|
23
|
+
defaultSpecifier = symbol;
|
|
24
|
+
} else if (imported === '*') {
|
|
25
|
+
namespaceSpecifier = `* as ${symbol}`;
|
|
26
|
+
} else {
|
|
27
|
+
let specifier = imported;
|
|
28
|
+
if (symbol !== imported) {
|
|
29
|
+
specifier += ` as ${symbol}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
namedSpecifiers.push(specifier);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ESModule syntax allows combining default and namespace specifiers, or default and named, but not all three.
|
|
37
|
+
|
|
38
|
+
let imported = '';
|
|
39
|
+
if (namespaceSpecifier) {
|
|
40
|
+
let s = namespaceSpecifier;
|
|
41
|
+
if (defaultSpecifier) {
|
|
42
|
+
s = `${defaultSpecifier}, ${namespaceSpecifier}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
res += `import ${s} from ${JSON.stringify(source)};\n`;
|
|
46
|
+
lines++;
|
|
47
|
+
} else if (defaultSpecifier) {
|
|
48
|
+
imported = defaultSpecifier;
|
|
49
|
+
if (namedSpecifiers.length > 0) {
|
|
50
|
+
imported += `, {${namedSpecifiers.join(', ')}}`;
|
|
51
|
+
}
|
|
52
|
+
} else if (namedSpecifiers.length > 0) {
|
|
53
|
+
imported = `{${namedSpecifiers.join(', ')}}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (imported.length > 0) {
|
|
57
|
+
res += `import ${imported} from ${JSON.stringify(source)};\n`;
|
|
58
|
+
lines++;
|
|
59
|
+
} else if (!namespaceSpecifier) {
|
|
60
|
+
res += `import ${JSON.stringify(source)};\n`;
|
|
61
|
+
lines++;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (res.length > 0) {
|
|
66
|
+
res += '\n';
|
|
67
|
+
lines++;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return [res, lines];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
buildBundlePostlude(): [string, number] {
|
|
74
|
+
let res = '';
|
|
75
|
+
let lines = 0;
|
|
76
|
+
let exportSpecifiers = [];
|
|
77
|
+
for (let {
|
|
78
|
+
asset,
|
|
79
|
+
exportSymbol,
|
|
80
|
+
local,
|
|
81
|
+
exportAs,
|
|
82
|
+
} of this.packager.exportedSymbols.values()) {
|
|
83
|
+
if (this.packager.wrappedAssets.has(asset.id)) {
|
|
84
|
+
let obj = `parcelRequire("${this.packager.bundleGraph.getAssetPublicId(
|
|
85
|
+
asset,
|
|
86
|
+
)}")`;
|
|
87
|
+
res += `\nvar ${local} = ${this.packager.getPropertyAccess(
|
|
88
|
+
obj,
|
|
89
|
+
exportSymbol,
|
|
90
|
+
)};`;
|
|
91
|
+
lines++;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (let as of exportAs) {
|
|
95
|
+
let specifier = local;
|
|
96
|
+
if (exportAs !== local) {
|
|
97
|
+
specifier += ` as ${as}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
exportSpecifiers.push(specifier);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (exportSpecifiers.length > 0) {
|
|
105
|
+
res += `\nexport {${exportSpecifiers.join(', ')}};`;
|
|
106
|
+
lines++;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return [res, lines];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type {
|
|
3
|
+
ScopeHoistingPackager,
|
|
4
|
+
OutputFormat,
|
|
5
|
+
} from './ScopeHoistingPackager';
|
|
6
|
+
|
|
7
|
+
export class GlobalOutputFormat implements OutputFormat {
|
|
8
|
+
packager: ScopeHoistingPackager;
|
|
9
|
+
|
|
10
|
+
constructor(packager: ScopeHoistingPackager) {
|
|
11
|
+
this.packager = packager;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
buildBundlePrelude(): [string, number] {
|
|
15
|
+
let prelude = this.packager.bundle.env.supports('arrow-functions', true)
|
|
16
|
+
? '(() => {\n'
|
|
17
|
+
: '(function () {\n';
|
|
18
|
+
return [prelude, 1];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
buildBundlePostlude(): [string, number] {
|
|
22
|
+
return ['})();', 0];
|
|
23
|
+
}
|
|
24
|
+
}
|