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

Implement support for classic scripts and automatic module/nomodule #6247

Merged
merged 15 commits into from
Jun 19, 2021
Merged
1 change: 1 addition & 0 deletions flow-libs/posthtml-parser.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ declare module 'posthtml-parser' {
options?: {
lowerCaseAttributeNames?: boolean,
lowerCaseTags?: boolean,
sourceLocations?: boolean,
...
}
) => PostHTMLNode;
Expand Down
7 changes: 6 additions & 1 deletion flow-libs/posthtml.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ declare module 'posthtml' {
tag: string,
attrs?: {[string]: string, ...},
content?: Array<string>,
location?: {
start: {|line: number, column: number|},
end: {|line: number, column: number|},
...
},
...
};

Expand All @@ -26,7 +31,7 @@ declare module 'posthtml' {
...
};

declare var walk: (fn: (node: PostHTMLNode) => PostHTMLNode) => void;
declare var walk: (fn: (node: PostHTMLNode) => PostHTMLNode | PostHTMLNode[]) => void;
declare var process: (
tree: PostHTMLTree | string,
options: ?PostHTMLOptions,
Expand Down
5 changes: 5 additions & 0 deletions packages/core/core/src/Environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ export function createEnvironment({
engines,
includeNodeModules,
outputFormat,
sourceType,
devongovett marked this conversation as resolved.
Show resolved Hide resolved
shouldOptimize = false,
isLibrary = false,
shouldScopeHoist = false,
sourceMap,
loc,
}: EnvironmentOptions = {}): Environment {
if (context == null) {
if (engines?.node) {
Expand Down Expand Up @@ -84,10 +86,12 @@ export function createEnvironment({
engines,
includeNodeModules,
outputFormat,
sourceType: sourceType ?? 'module',
devongovett marked this conversation as resolved.
Show resolved Hide resolved
isLibrary,
shouldOptimize,
shouldScopeHoist,
sourceMap,
loc,
};

res.id = getEnvironmentHash(res);
Expand Down Expand Up @@ -118,6 +122,7 @@ function getEnvironmentHash(env: Environment): string {
env.engines,
env.includeNodeModules,
env.outputFormat,
env.sourceType,
env.isLibrary,
env.shouldScopeHoist,
env.sourceMap,
Expand Down
11 changes: 9 additions & 2 deletions packages/core/core/src/applyRuntimes.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {PluginLogger} from '@parcel/logger';
import {hashString} from '@parcel/hash';
import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic';
import {dependencyToInternalDependency} from './public/Dependency';
import {mergeEnvironments} from './Environment';
import createAssetGraphRequest from './requests/AssetGraphRequest';
import {createDevDependency, runDevDepRequest} from './requests/DevDepRequest';

Expand Down Expand Up @@ -77,7 +78,13 @@ export default async function applyRuntimes({

if (applied) {
let runtimeAssets = Array.isArray(applied) ? applied : [applied];
for (let {code, dependency, filePath, isEntry} of runtimeAssets) {
for (let {
code,
dependency,
filePath,
isEntry,
env,
} of runtimeAssets) {
let sourceName = path.join(
path.dirname(filePath),
`runtime-${hashString(code)}.${bundle.type}`,
Expand All @@ -86,7 +93,7 @@ export default async function applyRuntimes({
let assetGroup = {
code,
filePath: sourceName,
env: bundle.env,
env: mergeEnvironments(bundle.env, env),
// Runtime assets should be considered source, as they should be
// e.g. compiled to run in the target environment
isSource: true,
Expand Down
82 changes: 66 additions & 16 deletions packages/core/core/src/public/Environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
import type {
Environment as IEnvironment,
EnvironmentContext,
EnvironmentFeature,
Engines,
OutputFormat,
PackageName,
VersionMap,
SourceLocation,
SourceType,
TargetSourceMapOptions,
} from '@parcel/types';
import type {Environment as InternalEnvironment} from '../types';
Expand Down Expand Up @@ -45,17 +48,41 @@ const ALL_BROWSERS = [
'kaios',
];

const ESMODULE_BROWSERS = {
edge: '16',
firefox: '60',
chrome: '61',
safari: '11',
opera: '48',
ios: '11',
android: '76',
and_chr: '76',
and_ff: '68',
samsung: '8.2',
const supportData = {
esmodules: {
edge: '16',
firefox: '60',
chrome: '61',
safari: '11',
opera: '48',
ios: '11',
android: '76',
and_chr: '76',
and_ff: '68',
samsung: '8.2',
},
'dynamic-import': {
edge: '76',
firefox: '67',
chrome: '63',
safari: '11.1',
opera: '50',
ios: '11.3',
android: '63',
and_chr: '63',
and_ff: '67',
samsung: '8',
},
'worker-module': {
edge: '80',
chrome: '80',
opera: '67',
android: '81',
and_chr: '86',
},
'service-worker-module': {
// TODO: Safari 14.1??
},
};

const internalEnvironmentToEnvironment: WeakMap<
Expand Down Expand Up @@ -110,6 +137,10 @@ export default class Environment implements IEnvironment {
return this.#environment.outputFormat;
}

get sourceType(): ?SourceType {
devongovett marked this conversation as resolved.
Show resolved Hide resolved
return this.#environment.sourceType;
}

get isLibrary(): boolean {
return this.#environment.isLibrary;
}
Expand All @@ -126,6 +157,10 @@ export default class Environment implements IEnvironment {
return this.#environment.sourceMap;
}

get loc(): ?SourceLocation {
return this.#environment.loc;
}

isBrowser(): boolean {
return BROWSER_ENVS.has(this.#environment.context);
}
Expand All @@ -146,7 +181,10 @@ export default class Environment implements IEnvironment {
return WORKER_ENVS.has(this.#environment.context);
}

matchesEngines(minVersions: VersionMap): boolean {
matchesEngines(
minVersions: VersionMap,
defaultValue?: boolean = false,
): boolean {
// Determine if the environment matches some minimum version requirements.
// For browsers, we run a browserslist query with and without the minimum
// required browsers and compare the lists. For node, we just check semver.
Expand All @@ -159,18 +197,30 @@ export default class Environment implements IEnvironment {

// If outputting esmodules, exclude browsers without support.
if (this.outputFormat === 'esmodule') {
browsers = [...browsers, ...getExcludedBrowsers(ESMODULE_BROWSERS)];
browsers = [...browsers, ...getExcludedBrowsers(supportData.esmodules)];
}

let matchedBrowsers = browserslist(browsers);
let minBrowsers = getExcludedBrowsers(minVersions);
let withoutMinBrowsers = browserslist([...browsers, ...minBrowsers]);
return matchedBrowsers.length === withoutMinBrowsers.length;
} else if (this.isNode() && this.engines.node != null && minVersions.node) {
return !semver.intersects(`< ${minVersions.node}`, this.engines.node);
} else if (this.isNode() && this.engines.node != null) {
return (
minVersions.node != null &&
!semver.intersects(`< ${minVersions.node}`, this.engines.node)
);
}

return defaultValue;
}

supports(feature: EnvironmentFeature, defaultValue?: boolean): boolean {
let engines = supportData[feature];
if (!engines) {
throw new Error('Unknown environment feature: ' + feature);
}

return false;
return this.matchesEngines(engines, defaultValue);
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/core/src/public/Symbols.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class AssetSymbols implements IAssetSymbols {

exportSymbols(): Iterable<ISymbol> {
// $FlowFixMe
return this.#value.symbols.keys();
return this.#value.symbols?.keys() ?? [];
}
// $FlowFixMe
[Symbol.iterator]() {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/core/src/requests/TargetRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ export class TargetResolver {
let config = browserslist.parseConfig(contents);
let browserslistBrowsers = config[env] || config.defaults;

if (browserslistBrowsers) {
if (browserslistBrowsers?.length > 0) {
pkgEngines = {
...pkgEngines,
browsers: browserslistBrowsers,
Expand Down
3 changes: 3 additions & 0 deletions packages/core/core/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
ReporterEvent,
ServerOptions,
SourceLocation,
SourceType,
Stats,
Symbol,
TargetSourceMapOptions,
Expand Down Expand Up @@ -68,10 +69,12 @@ export type Environment = {|
| Array<PackageName>
| {[PackageName]: boolean, ...},
outputFormat: OutputFormat,
sourceType: ?SourceType,
isLibrary: boolean,
shouldOptimize: boolean,
shouldScopeHoist: boolean,
sourceMap: ?TargetSourceMapOptions,
loc: ?SourceLocation,
|};

export type Target = {|
Expand Down
20 changes: 15 additions & 5 deletions packages/core/core/test/Environment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {createEnvironment} from '../src/Environment';
describe('Environment', () => {
it('assigns a default environment with nothing passed', () => {
assert.deepEqual(createEnvironment(), {
id: '1051b306b4fe6e64',
id: '2163092a3dd83a5f',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😞

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be neat if we used/made something along the lines of Jest's stringMatching matcher: https://jestjs.io/docs/expect#expectstringmatchingstring--regexp

context: 'browser',
engines: {
browsers: ['> 0.25%'],
Expand All @@ -17,12 +17,14 @@ describe('Environment', () => {
shouldOptimize: false,
shouldScopeHoist: false,
sourceMap: undefined,
loc: undefined,
sourceType: 'module',
});
});

it('assigns a node context if a node engine is given', () => {
assert.deepEqual(createEnvironment({engines: {node: '>= 10.0.0'}}), {
id: '3938a02d672f6a6b',
id: '36da7887c1caf6e9',
context: 'node',
engines: {
node: '>= 10.0.0',
Expand All @@ -33,14 +35,16 @@ describe('Environment', () => {
shouldOptimize: false,
shouldScopeHoist: false,
sourceMap: undefined,
loc: undefined,
sourceType: 'module',
});
});

it('assigns a browser context if browser engines are given', () => {
assert.deepEqual(
createEnvironment({engines: {browsers: ['last 1 version']}}),
{
id: '7b484221d8006458',
id: '74e2019b893d5a25',
context: 'browser',
engines: {
browsers: ['last 1 version'],
Expand All @@ -51,13 +55,15 @@ describe('Environment', () => {
shouldOptimize: false,
shouldScopeHoist: false,
sourceMap: undefined,
loc: undefined,
sourceType: 'module',
},
);
});

it('assigns default engines for node', () => {
assert.deepEqual(createEnvironment({context: 'node'}), {
id: '6e21f46e99d1eeb1',
id: 'e9e007a350f036f2',
context: 'node',
engines: {
node: '>= 8.0.0',
Expand All @@ -68,12 +74,14 @@ describe('Environment', () => {
shouldOptimize: false,
shouldScopeHoist: false,
sourceMap: undefined,
loc: undefined,
sourceType: 'module',
});
});

it('assigns default engines for browsers', () => {
assert.deepEqual(createEnvironment({context: 'browser'}), {
id: '1051b306b4fe6e64',
id: '2163092a3dd83a5f',
context: 'browser',
engines: {
browsers: ['> 0.25%'],
Expand All @@ -84,6 +92,8 @@ describe('Environment', () => {
shouldOptimize: false,
shouldScopeHoist: false,
sourceMap: undefined,
loc: undefined,
sourceType: 'module',
});
});
});
Loading