Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encoded inline bundles #3726

Merged
merged 19 commits into from
Nov 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions flow-libs/isbinaryfile.js.flow
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// @flow

// Derived from the README for isbinaryfile, available at:
// https://github.com/gjtorikian/isBinaryFile#readme
// Which is licensed MIT.

declare module 'isbinaryfile' {
declare export function isBinaryFile(
buffer: Buffer,
bytesToRead?: number
): Promise<boolean>;
declare export function isBinaryFileSync(
buffer: Buffer,
bytesToRead?: number
): boolean;
}
7 changes: 4 additions & 3 deletions packages/bundlers/default/src/DefaultBundler.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ export default new Bundler({
let resolution = bundleGraph.getDependencyResolution(dependency);

if (
dependency.isEntry ||
dependency.isAsync ||
resolution?.isIsolated
(dependency.isEntry && resolution) ||
(dependency.isAsync && resolution) ||
resolution?.isIsolated ||
resolution?.isInline
) {
let bundleGroup = bundleGraph.createBundleGroup(
dependency,
Expand Down
3 changes: 3 additions & 0 deletions packages/configs/default/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
"bundler": "@parcel/bundler-default",
"transforms": {
"types:*.{ts,tsx}": ["@parcel/transformer-typescript-types"],
"bundle-text:*": ["@parcel/transformer-inline-string", "..."],
"data-url:*": ["@parcel/transformer-inline-string", "..."],
"*.{js,mjs,jsm,jsx,es6,ts,tsx}": [
"@parcel/transformer-babel",
"@parcel/transformer-js"
Expand Down Expand Up @@ -29,6 +31,7 @@
"node": ["@parcel/runtime-js"]
},
"optimizers": {
"data-url:*": ["...", "@parcel/optimizer-data-url"],
"*.css": ["@parcel/optimizer-cssnano"],
"*.js": ["@parcel/optimizer-terser"],
"*.html": ["@parcel/optimizer-htmlnano"]
Expand Down
2 changes: 2 additions & 0 deletions packages/configs/default/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@parcel/bundler-default": "^2.0.0-alpha.2.1",
"@parcel/namer-default": "^2.0.0-alpha.2.1",
"@parcel/optimizer-cssnano": "^2.0.0-alpha.2.1",
"@parcel/optimizer-data-url": "^2.0.0-alpha.2.1",
"@parcel/optimizer-terser": "^2.0.0-alpha.2.1",
"@parcel/optimizer-htmlnano": "^2.0.0-alpha.2.1",
"@parcel/packager-css": "^2.0.0-alpha.2.1",
Expand All @@ -34,6 +35,7 @@
"@parcel/transformer-coffeescript": "^2.0.0-alpha.2.1",
"@parcel/transformer-css": "^2.0.0-alpha.2.1",
"@parcel/transformer-html": "^2.0.0-alpha.2.1",
"@parcel/transformer-inline-string": "^2.0.0-alpha.2.1",
"@parcel/transformer-js": "^2.0.0-alpha.2.1",
"@parcel/transformer-json": "^2.0.0-alpha.2.1",
"@parcel/transformer-less": "^2.0.0-alpha.2.1",
Expand Down
4 changes: 4 additions & 0 deletions packages/configs/default/test/config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ function collectConfigPackageReferences(

for (let value of Object.values(configSection)) {
if (typeof value === 'string') {
if (value === '...') {
continue;
}

references.add(value);
} else if (configSection != null && typeof configSection === 'object') {
collectConfigPackageReferences(value, references);
Expand Down
5 changes: 5 additions & 0 deletions packages/core/core/src/InternalAsset.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type AssetOptions = {|
outputHash?: string,
env: Environment,
meta?: Meta,
pipeline?: ?string,
stats: Stats,
symbols?: Map<Symbol, Symbol>,
sideEffects?: boolean,
Expand Down Expand Up @@ -72,6 +73,7 @@ export function createAsset(options: AssetOptions): Asset {
includedFiles: options.includedFiles || new Map(),
isSource: options.isSource,
outputHash: options.outputHash || '',
pipeline: options.pipeline,
env: options.env,
meta: options.meta || {},
stats: options.stats,
Expand Down Expand Up @@ -287,6 +289,9 @@ export default class InternalAsset {
: new Map(),
includedFiles: new Map(this.value.includedFiles),
meta: {...this.value.meta, ...result.meta},
pipeline:
result.pipeline ??
(this.value.type === result.type ? this.value.pipeline : null),
stats: {
time: 0,
size
Expand Down
92 changes: 6 additions & 86 deletions packages/core/core/src/PackagerRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,10 @@ import type ParcelConfig from './ParcelConfig';
import type InternalBundleGraph from './BundleGraph';
import type {FileSystem, FileOptions} from '@parcel/fs';

import {
urlJoin,
md5FromObject,
md5FromString,
blobToStream
} from '@parcel/utils';
import {md5FromObject, md5FromString, blobToStream} from '@parcel/utils';
import {PluginLogger} from '@parcel/logger';
import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic';
import {Readable} from 'stream';
import invariant from 'assert';
import nullthrows from 'nullthrows';
import path from 'path';
import url from 'url';
Expand Down Expand Up @@ -233,7 +227,7 @@ export default class PackagerRunner {

let packager = await this.config.getPackager(bundle.filePath);
try {
let packaged = await packager.plugin.package({
return await packager.plugin.package({
bundle,
bundleGraph: new BundleGraph(bundleGraph, this.options),
getSourceMapReference: map => {
Expand All @@ -260,17 +254,6 @@ export default class PackagerRunner {
);
}
});

return {
contents:
typeof packaged.contents === 'string'
? replaceReferences(
packaged.contents,
generateDepToBundlePath(internalBundle, bundleGraph)
)
: packaged.contents,
map: packaged.map
};
} catch (e) {
throw new ThrowableDiagnostic({
diagnostic: errorToDiagnostic(e, packager.name)
Expand All @@ -285,7 +268,10 @@ export default class PackagerRunner {
map?: ?SourceMap
): Promise<BundleResult> {
let bundle = new NamedBundle(internalBundle, bundleGraph, this.options);
let optimizers = await this.config.getOptimizers(bundle.filePath);
let optimizers = await this.config.getOptimizers(
bundle.filePath,
internalBundle.pipeline
);
if (!optimizers.length) {
return {contents, map};
}
Expand Down Expand Up @@ -490,72 +476,6 @@ function writeFileStream(
});
}

/*
* Build a mapping from async, url dependency ids to web-friendly relative paths
* to their bundles. These will be relative to the current bundle if `publicUrl`
* is not provided. If `publicUrl` is provided, the paths will be joined to it.
*
* These are used to translate any placeholder dependency ids written during
* transformation back to a path that can be loaded in a browser (such as
* in a "raw" loader or any transformed dependencies referred to by url).
*/
function generateDepToBundlePath(
bundle: InternalBundle,
bundleGraph: InternalBundleGraph
): Map<string, FilePath> {
let depToBundlePath: Map<string, FilePath> = new Map();
bundleGraph.traverseBundle(bundle, node => {
if (node.type !== 'dependency') {
return;
}

let dep = node.value;
if (!dep.isURL || !dep.isAsync) {
return;
}

let [bundleGroupNode] = bundleGraph._graph.getNodesConnectedFrom(node);
invariant(bundleGroupNode && bundleGroupNode.type === 'bundle_group');

let [entryBundleNode] = bundleGraph._graph.getNodesConnectedFrom(
bundleGroupNode,
'bundle'
);
invariant(entryBundleNode && entryBundleNode.type === 'bundle');

let entryBundle = entryBundleNode.value;
depToBundlePath.set(
dep.id,
urlJoin(
nullthrows(entryBundle.target).publicUrl ?? '/',
nullthrows(entryBundle.name)
)
);
});

return depToBundlePath;
}

// replace references to url dependencies with relative paths to their
// corresponding bundles.
// TODO: This likely alters the length of the column in the source text.
// Update any sourcemaps accordingly.
function replaceReferences(
code: string,
depToBundlePath: Map<string, FilePath>
): string {
let output = code;
for (let [depId, replacement] of depToBundlePath) {
let split = output.split(depId);
if (split.length > 1) {
// the dependency id was found in the text. replace it.
output = split.join(replacement);
}
}

return output;
}

function getContentKey(cacheKey: string) {
return md5FromString(`${cacheKey}:content`);
}
Expand Down
22 changes: 12 additions & 10 deletions packages/core/core/src/ParcelConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ export default class ParcelConfig {
return this.loadPlugins<Validator>(names);
}

getNamedPipelines(): $ReadOnlyArray<string> {
return Object.keys(this.transforms)
.filter(glob => glob.includes(':'))
.map(glob => glob.split(':')[0]);
}

getTransformers(filePath: FilePath, pipeline?: ?string) {
return this.loadPlugins<Transformer>(
this.getTransformerNames(filePath, pipeline)
Expand Down Expand Up @@ -215,26 +221,22 @@ export default class ParcelConfig {
};
}

getOptimizerNames(filePath: FilePath): Array<string> {
let optimizers: ?Pipeline = this.matchGlobMapPipelines(
filePath,
this.optimizers
getOptimizerNames(filePath: FilePath, pipeline: ?string): Array<string> {
return (
this.matchGlobMapPipelines(filePath, this.optimizers, pipeline) ?? []
);
if (!optimizers) {
return [];
}
return optimizers;
}

getOptimizers(
filePath: FilePath
filePath: FilePath,
pipeline: ?string
): Promise<
Array<{|
name: string,
plugin: Optimizer
|}>
> {
let optimizers = this.getOptimizerNames(filePath);
let optimizers = this.getOptimizerNames(filePath, pipeline);
if (optimizers.length === 0) {
return Promise.resolve([]);
}
Expand Down
38 changes: 36 additions & 2 deletions packages/core/core/src/ResolverRunner.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// @flow

import type {AssetRequestDesc, Dependency, ParcelOptions} from './types';
import type ParcelConfig from './ParcelConfig';

import {PluginLogger} from '@parcel/logger';
import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic';
import path from 'path';
import type ParcelConfig from './ParcelConfig';
import URL from 'url';

import {report} from './ReporterRunner';
import PublicDependency from './public/Dependency';
import PluginOptions from './public/PluginOptions';
Expand Down Expand Up @@ -36,9 +38,41 @@ export default class ResolverRunner {

let resolvers = await this.config.getResolvers();

let pipeline;
let filePath;
let validPipelines = new Set(this.config.getNamedPipelines());
if (
// Don't consider absolute paths. Absolute paths are only supported for entries,
// and include e.g. `C:\` on Windows, conflicting with pipelines.
!path.isAbsolute(dependency.moduleSpecifier) &&
dependency.moduleSpecifier.includes(':')
) {
[pipeline, filePath] = dependency.moduleSpecifier.split(':');
if (!validPipelines.has(pipeline)) {
if (dep.isURL) {
// This may be a url protocol or scheme rather than a pipeline, such as
// `url('http://example.com/foo.png')`
return null;
} else {
throw new Error(`Unknown pipeline ${pipeline}.`);
}
}
} else {
filePath = dependency.moduleSpecifier;
}

if (dependency.isURL) {
let parsed = URL.parse(filePath);
if (typeof parsed.pathname !== 'string') {
throw new Error('Received URL without a pathname.');
}
filePath = decodeURIComponent(parsed.pathname);
}

for (let resolver of resolvers) {
try {
let result = await resolver.plugin.resolve({
filePath,
dependency: dep,
options: this.pluginOptions,
logger: new PluginLogger({origin: resolver.name})
Expand All @@ -54,7 +88,7 @@ export default class ResolverRunner {
sideEffects: result.sideEffects,
code: result.code,
env: dependency.env,
pipeline: dependency.pipeline
pipeline: pipeline ?? dependency.pipeline
};
}
} catch (e) {
Expand Down
4 changes: 3 additions & 1 deletion packages/core/core/src/Transformation.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default class Transformation {
}

async loadAsset(): Promise<InternalAsset> {
let {filePath, env, code, sideEffects} = this.request;
let {filePath, env, code, pipeline, sideEffects} = this.request;
let {content, size, hash, isSource} = await summarizeRequest(
this.options.inputFS,
this.request
Expand All @@ -128,6 +128,7 @@ export default class Transformation {
isSource,
type: path.extname(filePath).slice(1),
hash,
pipeline,
env,
stats: {
time: 0,
Expand Down Expand Up @@ -594,6 +595,7 @@ function normalizeAssets(
env: result.env,
isIsolated: result.isIsolated,
isInline: result.isInline,
pipeline: internalAsset.value.pipeline,
meta: result.meta,
uniqueKey: internalAsset.value.uniqueKey
};
Expand Down
Loading