Skip to content

Commit f682727

Browse files
committed
Make it a non-breaking change
1 parent 14f7bee commit f682727

File tree

8 files changed

+58
-22
lines changed

8 files changed

+58
-22
lines changed

packages/configs/default/index.json

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@
88
"@parcel/transformer-worklet",
99
"..."
1010
],
11-
"*.mdx": ["@parcel/transformer-js"],
12-
"*.{js,mjs,jsm,jsx,es6,cjs,ts,tsx,mdx}": [
11+
"*.mdx": [
12+
// For backward compatibility, include the old transformer
13+
// so it is used if already installed in the project.
14+
// Otherwise, the JS transformer will handle MDX.
15+
"@parcel/transformer-mdx",
16+
"@parcel/transformer-js"
17+
],
18+
"*.{js,mjs,jsm,jsx,es6,cjs,ts,tsx}": [
1319
"@parcel/transformer-babel",
1420
"@parcel/transformer-js",
1521
"@parcel/transformer-react-refresh-wrap"

packages/configs/default/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@
7474
"@parcel/transformer-xml": "2.13.3",
7575
"@parcel/transformer-yaml": "2.13.3"
7676
},
77+
"optionalParcelDependencies": [
78+
"@parcel/transformer-mdx"
79+
],
7780
"peerDependencies": {
7881
"@parcel/core": "^2.13.3"
7982
}

packages/configs/default/test/config.test.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
import assert from 'assert';
44

5-
import config from '../';
65
import packageJson from '../package.json';
6+
import json5 from 'json5';
7+
import fs from 'fs';
78

89
describe('@parcel/config-default', () => {
910
let packageJsonDependencyNames: Set<string>;
@@ -13,7 +14,11 @@ describe('@parcel/config-default', () => {
1314
packageJsonDependencyNames = new Set([
1415
...Object.keys(packageJson.dependencies || {}),
1516
...Object.keys(packageJson.parcelDependencies || {}),
17+
...packageJson.optionalParcelDependencies,
1618
]);
19+
let config = json5.parse(
20+
fs.readFileSync(__dirname + '/../index.json', 'utf8'),
21+
);
1722
configPackageReferences = collectConfigPackageReferences(config);
1823
});
1924

packages/core/core/src/ParcelConfig.js

+12-6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import ThrowableDiagnostic, {
2828
generateJSONCodeHighlights,
2929
} from '@parcel/diagnostic';
3030
import json5 from 'json5';
31+
import nullthrows from 'nullthrows';
3132

3233
import {globToRegex} from '@parcel/utils';
3334
import {basename} from 'path';
@@ -121,7 +122,7 @@ export default class ParcelConfig {
121122
version: Semver,
122123
resolveFrom: ProjectPath,
123124
range: ?SemverRange,
124-
|}> {
125+
|} | null> {
125126
let plugin = this.pluginCache.get(node.packageName);
126127
if (plugin) {
127128
return plugin;
@@ -138,8 +139,11 @@ export default class ParcelConfig {
138139
return plugin;
139140
}
140141

141-
async loadPlugin<T>(node: ParcelPluginNode): Promise<LoadedPlugin<T>> {
142+
async loadPlugin<T>(node: ParcelPluginNode): Promise<LoadedPlugin<T> | null> {
142143
let plugin = await this._loadPlugin(node);
144+
if (!plugin) {
145+
return null;
146+
}
143147
return {
144148
...plugin,
145149
name: node.packageName,
@@ -151,10 +155,12 @@ export default class ParcelConfig {
151155
this.pluginCache.delete(packageName);
152156
}
153157

154-
loadPlugins<T>(
158+
async loadPlugins<T>(
155159
plugins: PureParcelConfigPipeline,
156160
): Promise<Array<LoadedPlugin<T>>> {
157-
return Promise.all(plugins.map(p => this.loadPlugin<T>(p)));
161+
return (await Promise.all(plugins.map(p => this.loadPlugin<T>(p)))).filter(
162+
Boolean,
163+
);
158164
}
159165

160166
async getResolvers(): Promise<Array<LoadedPlugin<Resolver<mixed>>>> {
@@ -228,7 +234,7 @@ export default class ParcelConfig {
228234
);
229235
}
230236

231-
return this.loadPlugin<Bundler<mixed>>(this.bundler);
237+
return nullthrows(await this.loadPlugin<Bundler<mixed>>(this.bundler));
232238
}
233239

234240
async getNamers(): Promise<Array<LoadedPlugin<Namer<mixed>>>> {
@@ -265,7 +271,7 @@ export default class ParcelConfig {
265271
'/packagers',
266272
);
267273
}
268-
return this.loadPlugin<Packager<mixed, mixed>>(packager);
274+
return nullthrows(await this.loadPlugin<Packager<mixed, mixed>>(packager));
269275
}
270276

271277
_getOptimizerNodes(

packages/core/core/src/assetUtils.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,16 @@ async function _generateFromAST(asset: CommittedAsset | UncommittedAsset) {
152152
}
153153

154154
let pluginName = nullthrows(asset.value.plugin);
155-
let {plugin} = await loadPlugin<Transformer<mixed>>(
156-
pluginName,
157-
fromProjectPath(
158-
asset.options.projectRoot,
159-
nullthrows(asset.value.configPath),
155+
let {plugin} = nullthrows(
156+
await loadPlugin<Transformer<mixed>>(
157+
pluginName,
158+
fromProjectPath(
159+
asset.options.projectRoot,
160+
nullthrows(asset.value.configPath),
161+
),
162+
nullthrows(asset.value.configKeyPath),
163+
asset.options,
160164
),
161-
nullthrows(asset.value.configKeyPath),
162-
asset.options,
163165
);
164166
let generate = plugin.generate?.bind(plugin);
165167
if (!generate) {

packages/core/core/src/loadParcelPlugin.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@ export default async function loadPlugin<T>(
3131
version: Semver,
3232
resolveFrom: ProjectPath,
3333
range: ?SemverRange,
34-
|}> {
34+
|} | null> {
3535
let resolveFrom = configPath;
3636
let range;
37-
if (resolveFrom.includes(NODE_MODULES)) {
37+
let isOptional = false;
38+
if (
39+
resolveFrom.includes(NODE_MODULES) ||
40+
(process.env.PARCEL_BUILD_ENV !== 'production' &&
41+
/packages[/\\]configs/.test(resolveFrom))
42+
) {
3843
// Config packages can reference plugins, but cannot contain other plugins within them.
3944
// This forces every published plugin to be published separately so they can be mixed and matched if needed.
4045
if (pluginName.startsWith('.')) {
@@ -75,8 +80,11 @@ export default async function loadPlugin<T>(
7580
// If not in the config's dependencies, the plugin will be auto installed with
7681
// the version declared in "parcelDependencies".
7782
range = configPkg.config.parcelDependencies?.[pluginName];
83+
isOptional =
84+
Array.isArray(configPkg.config.optionalParcelDependencies) &&
85+
configPkg.config.optionalParcelDependencies.includes(pluginName);
7886

79-
if (range == null) {
87+
if (range == null && !isOptional) {
8088
let contents = await options.inputFS.readFile(
8189
configPkg.files[0].filePath,
8290
'utf8',
@@ -122,7 +130,7 @@ export default async function loadPlugin<T>(
122130
pluginName,
123131
resolveFrom,
124132
{
125-
shouldAutoInstall: options.shouldAutoInstall,
133+
shouldAutoInstall: options.shouldAutoInstall && !isOptional,
126134
range,
127135
},
128136
));
@@ -131,6 +139,10 @@ export default async function loadPlugin<T>(
131139
throw err;
132140
}
133141

142+
if (isOptional) {
143+
return null;
144+
}
145+
134146
let configContents = await options.inputFS.readFile(configPath, 'utf8');
135147
let alternatives = await findAlternativeNodeModules(
136148
options.inputFS,

packages/core/core/test/ParcelConfigRequest.test.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import {
1616
import {validatePackageName} from '../src/ParcelConfig.schema';
1717
import {DEFAULT_OPTIONS, relative} from './test-utils';
1818
import {toProjectPath} from '../src/projectPath';
19+
import json5 from 'json5';
20+
import fs from 'fs';
1921

2022
describe('ParcelConfigRequest', () => {
2123
describe('validatePackageName', () => {
@@ -696,7 +698,7 @@ describe('ParcelConfigRequest', () => {
696698
let defaultConfigPath = require.resolve('@parcel/config-default');
697699
let defaultConfig = await processConfig(
698700
{
699-
...require('@parcel/config-default'),
701+
...json5.parse(fs.readFileSync(defaultConfigPath, 'utf8')),
700702
filePath: defaultConfigPath,
701703
},
702704
DEFAULT_OPTIONS,

packages/transformers/js/core/src/dependency_collector.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1913,7 +1913,7 @@ try {{
19131913
kind: DependencyKind::Require,
19141914
specifier: "other".into(),
19151915
attributes: None,
1916-
flags: DependencyFlags::empty(),
1916+
flags: DependencyFlags::OPTIONAL,
19171917
source_type: Some(SourceType::Module),
19181918
placeholder: Some(hash),
19191919
..items[0].clone()

0 commit comments

Comments
 (0)