Son CV dans un terminal web en Javascript!
https://terminal-cv.gregandev.fr
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
6.8 KiB
233 lines
6.8 KiB
2 years ago
|
// @flow strict-local
|
||
|
import type {BundleGraph, PluginOptions, NamedBundle} from '@parcel/types';
|
||
|
|
||
|
import {PromiseQueue, relativeBundlePath, countLines} from '@parcel/utils';
|
||
|
import SourceMap from '@parcel/source-map';
|
||
|
import invariant from 'assert';
|
||
|
import path from 'path';
|
||
|
import fs from 'fs';
|
||
|
import {replaceScriptDependencies, getSpecifier} from './utils';
|
||
|
|
||
|
const PRELUDE = fs
|
||
|
.readFileSync(path.join(__dirname, 'dev-prelude.js'), 'utf8')
|
||
|
.trim()
|
||
|
.replace(/;$/, '');
|
||
|
|
||
|
export class DevPackager {
|
||
|
options: PluginOptions;
|
||
|
bundleGraph: BundleGraph<NamedBundle>;
|
||
|
bundle: NamedBundle;
|
||
|
parcelRequireName: string;
|
||
|
|
||
|
constructor(
|
||
|
options: PluginOptions,
|
||
|
bundleGraph: BundleGraph<NamedBundle>,
|
||
|
bundle: NamedBundle,
|
||
|
parcelRequireName: string,
|
||
|
) {
|
||
|
this.options = options;
|
||
|
this.bundleGraph = bundleGraph;
|
||
|
this.bundle = bundle;
|
||
|
this.parcelRequireName = parcelRequireName;
|
||
|
}
|
||
|
|
||
|
async package(): Promise<{|contents: string, map: ?SourceMap|}> {
|
||
|
// Load assets
|
||
|
let queue = new PromiseQueue({maxConcurrent: 32});
|
||
|
this.bundle.traverse(node => {
|
||
|
if (node.type === 'asset') {
|
||
|
queue.add(async () => {
|
||
|
let [code, mapBuffer] = await Promise.all([
|
||
|
node.value.getCode(),
|
||
|
this.bundle.env.sourceMap && node.value.getMapBuffer(),
|
||
|
]);
|
||
|
return {code, mapBuffer};
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
let results = await queue.run();
|
||
|
|
||
|
let assets = '';
|
||
|
let i = 0;
|
||
|
let first = true;
|
||
|
let map = new SourceMap(this.options.projectRoot);
|
||
|
|
||
|
let prefix = this.getPrefix();
|
||
|
let lineOffset = countLines(prefix);
|
||
|
let script: ?{|code: string, mapBuffer: ?Buffer|} = null;
|
||
|
|
||
|
this.bundle.traverse(node => {
|
||
|
let wrapped = first ? '' : ',';
|
||
|
|
||
|
if (node.type === 'dependency') {
|
||
|
let resolved = this.bundleGraph.getResolvedAsset(
|
||
|
node.value,
|
||
|
this.bundle,
|
||
|
);
|
||
|
if (resolved && resolved.type !== 'js') {
|
||
|
// if this is a reference to another javascript asset, we should not include
|
||
|
// its output, as its contents should already be loaded.
|
||
|
invariant(!this.bundle.hasAsset(resolved));
|
||
|
wrapped +=
|
||
|
JSON.stringify(this.bundleGraph.getAssetPublicId(resolved)) +
|
||
|
':[function() {},{}]';
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (node.type === 'asset') {
|
||
|
let asset = node.value;
|
||
|
invariant(
|
||
|
asset.type === 'js',
|
||
|
'all assets in a js bundle must be js assets',
|
||
|
);
|
||
|
|
||
|
// If this is the main entry of a script rather than a module, we need to hoist it
|
||
|
// outside the bundle wrapper function so that its variables are exposed as globals.
|
||
|
if (
|
||
|
this.bundle.env.sourceType === 'script' &&
|
||
|
asset === this.bundle.getMainEntry()
|
||
|
) {
|
||
|
script = results[i++];
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
let deps = {};
|
||
|
let dependencies = this.bundleGraph.getDependencies(asset);
|
||
|
for (let dep of dependencies) {
|
||
|
let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle);
|
||
|
if (this.bundleGraph.isDependencySkipped(dep)) {
|
||
|
deps[getSpecifier(dep)] = false;
|
||
|
} else if (resolved) {
|
||
|
deps[getSpecifier(dep)] =
|
||
|
this.bundleGraph.getAssetPublicId(resolved);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let {code, mapBuffer} = results[i];
|
||
|
let output = code || '';
|
||
|
wrapped +=
|
||
|
JSON.stringify(this.bundleGraph.getAssetPublicId(asset)) +
|
||
|
':[function(require,module,exports) {\n' +
|
||
|
output +
|
||
|
'\n},';
|
||
|
wrapped += JSON.stringify(deps);
|
||
|
wrapped += ']';
|
||
|
|
||
|
if (this.bundle.env.sourceMap) {
|
||
|
if (mapBuffer) {
|
||
|
map.addBuffer(mapBuffer, lineOffset);
|
||
|
} else {
|
||
|
map.addEmptyMap(
|
||
|
path
|
||
|
.relative(this.options.projectRoot, asset.filePath)
|
||
|
.replace(/\\+/g, '/'),
|
||
|
output,
|
||
|
lineOffset,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
lineOffset += countLines(output) + 1;
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
assets += wrapped;
|
||
|
first = false;
|
||
|
});
|
||
|
|
||
|
let entries = this.bundle.getEntryAssets();
|
||
|
let mainEntry = this.bundle.getMainEntry();
|
||
|
if (
|
||
|
(!this.isEntry() && this.bundle.env.outputFormat === 'global') ||
|
||
|
this.bundle.env.sourceType === 'script'
|
||
|
) {
|
||
|
// In async bundles we don't want the main entry to execute until we require it
|
||
|
// as there might be dependencies in a sibling bundle that hasn't loaded yet.
|
||
|
entries = entries.filter(a => a.id !== mainEntry?.id);
|
||
|
mainEntry = null;
|
||
|
}
|
||
|
|
||
|
let contents =
|
||
|
prefix +
|
||
|
'({' +
|
||
|
assets +
|
||
|
'},' +
|
||
|
JSON.stringify(
|
||
|
entries.map(asset => this.bundleGraph.getAssetPublicId(asset)),
|
||
|
) +
|
||
|
', ' +
|
||
|
JSON.stringify(
|
||
|
mainEntry ? this.bundleGraph.getAssetPublicId(mainEntry) : null,
|
||
|
) +
|
||
|
', ' +
|
||
|
JSON.stringify(this.parcelRequireName) +
|
||
|
')' +
|
||
|
'\n';
|
||
|
|
||
|
// The entry asset of a script bundle gets hoisted outside the bundle wrapper function
|
||
|
// so that its variables become globals. We need to replace any require calls for
|
||
|
// runtimes with a parcelRequire call.
|
||
|
if (this.bundle.env.sourceType === 'script' && script) {
|
||
|
let entryMap;
|
||
|
let mapBuffer = script.mapBuffer;
|
||
|
if (mapBuffer) {
|
||
|
entryMap = new SourceMap(this.options.projectRoot, mapBuffer);
|
||
|
}
|
||
|
contents += replaceScriptDependencies(
|
||
|
this.bundleGraph,
|
||
|
this.bundle,
|
||
|
script.code,
|
||
|
entryMap,
|
||
|
this.parcelRequireName,
|
||
|
);
|
||
|
if (this.bundle.env.sourceMap && entryMap) {
|
||
|
map.addSourceMap(entryMap, lineOffset);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
contents,
|
||
|
map,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
getPrefix(): string {
|
||
|
let interpreter: ?string;
|
||
|
let mainEntry = this.bundle.getMainEntry();
|
||
|
if (mainEntry && this.isEntry() && !this.bundle.target.env.isBrowser()) {
|
||
|
let _interpreter = mainEntry.meta.interpreter;
|
||
|
invariant(_interpreter == null || typeof _interpreter === 'string');
|
||
|
interpreter = _interpreter;
|
||
|
}
|
||
|
|
||
|
let importScripts = '';
|
||
|
if (this.bundle.env.isWorker()) {
|
||
|
let bundles = this.bundleGraph.getReferencedBundles(this.bundle);
|
||
|
for (let b of bundles) {
|
||
|
importScripts += `importScripts("${relativeBundlePath(
|
||
|
this.bundle,
|
||
|
b,
|
||
|
)}");\n`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (
|
||
|
// If the entry asset included a hashbang, repeat it at the top of the bundle
|
||
|
(interpreter != null ? `#!${interpreter}\n` : '') +
|
||
|
importScripts +
|
||
|
PRELUDE
|
||
|
);
|
||
|
}
|
||
|
|
||
|
isEntry(): boolean {
|
||
|
return (
|
||
|
!this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') ||
|
||
|
this.bundle.env.isIsolated() ||
|
||
|
this.bundle.bundleBehavior === 'isolated'
|
||
|
);
|
||
|
}
|
||
|
}
|