From 4eee1df30618350a9314f2c48fa4f1c41a3e65a9 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Tue, 11 May 2021 23:29:01 +0200 Subject: [PATCH 1/8] Use local require for `@babel/core` --- packages/transformers/babel/package.json | 9 +-- packages/transformers/babel/src/babel7.js | 14 +++- packages/transformers/babel/src/config.js | 23 +++++-- packages/transformers/babel/src/env.js | 69 ------------------- packages/transformers/babel/src/typescript.js | 25 ------- yarn.lock | 16 ----- 6 files changed, 32 insertions(+), 124 deletions(-) delete mode 100644 packages/transformers/babel/src/env.js delete mode 100644 packages/transformers/babel/src/typescript.js diff --git a/packages/transformers/babel/package.json b/packages/transformers/babel/package.json index e7d541c1c5e..ff86e7accb1 100644 --- a/packages/transformers/babel/package.json +++ b/packages/transformers/babel/package.json @@ -20,15 +20,12 @@ "parcel": "^2.0.0-beta.1" }, "dependencies": { + "@babel/core": "^7.12.0", "@babel/generator": "^7.9.0", "@babel/helper-compilation-targets": "^7.8.4", "@babel/plugin-transform-flow-strip-types": "^7.0.0", - "@babel/plugin-transform-typescript": "^7.4.5", - "@babel/preset-env": "^7.0.0", - "@babel/preset-react": "^7.0.0", "@babel/traverse": "^7.0.0", "@parcel/babel-ast-utils": "2.0.0-beta.2", - "@parcel/babel-preset-env": "2.0.0-beta.2", "@parcel/plugin": "2.0.0-beta.2", "@parcel/source-map": "2.0.0-alpha.4.21", "@parcel/utils": "2.0.0-beta.2", @@ -39,9 +36,7 @@ }, "devDependencies": { "@babel/core": "^7.12.0", + "@babel/preset-env": "^7.0.0", "@parcel/types": "2.0.0-beta.2" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" } } diff --git a/packages/transformers/babel/src/babel7.js b/packages/transformers/babel/src/babel7.js index 9e3a06a656f..5c34f6d72dd 100644 --- a/packages/transformers/babel/src/babel7.js +++ b/packages/transformers/babel/src/babel7.js @@ -3,7 +3,7 @@ import type {MutableAsset, AST, PluginOptions} from '@parcel/types'; import invariant from 'assert'; -import * as babel from '@babel/core'; +import * as internalBabelCore from '@babel/core'; import {relativeUrl} from '@parcel/utils'; import packageJson from '../package.json'; @@ -17,6 +17,14 @@ export default async function babel7( babelOptions: any, additionalPlugins: Array = [], ): Promise { + const babelCode = babelOptions.internal + ? internalBabelCore + : await options.packageManager.require('@babel/core', asset.filePath, { + range: '^7.12.0', + saveDev: true, + shouldAutoInstall: options.shouldAutoInstall, + }); + let config = { ...babelOptions.config, plugins: additionalPlugins.concat(babelOptions.config.plugins), @@ -53,13 +61,13 @@ export default async function babel7( let ast = await asset.getAST(); let res; if (ast) { - res = await babel.transformFromAstAsync( + res = await babelCode.transformFromAstAsync( ast.program, asset.isASTDirty() ? undefined : await asset.getCode(), config, ); } else { - res = await babel.transformAsync(await asset.getCode(), config); + res = await babelCode.transformAsync(await asset.getCode(), config); } if (res.ast) { diff --git a/packages/transformers/babel/src/config.js b/packages/transformers/babel/src/config.js index bac0e39c3cb..90c781144c7 100644 --- a/packages/transformers/babel/src/config.js +++ b/packages/transformers/babel/src/config.js @@ -2,9 +2,10 @@ import type {Config, PluginOptions} from '@parcel/types'; import type {PluginLogger} from '@parcel/logger'; +import typeof * as BabelCore from '@babel/core'; import path from 'path'; -import * as babelCore from '@babel/core'; +import * as internalBabelCore from '@babel/core'; import {md5FromObject, relativePath, resolveConfig} from '@parcel/utils'; import isJSX from './jsx'; @@ -55,10 +56,20 @@ export async function load( options.projectRoot, )) ) { - await buildDefaultBabelConfig(options, config); + await buildDefaultBabelConfig(internalBabelCore, options, config); return; } + const babelCore: BabelCore = await options.packageManager.require( + '@babel/core', + config.searchPath, + { + range: '^7.12.0', + saveDev: true, + shouldAutoInstall: options.shouldAutoInstall, + }, + ); + let babelOptions = { filename: config.searchPath, cwd: options.projectRoot, @@ -174,11 +185,15 @@ export async function load( config.setResultHash(md5FromObject(partialConfig.options)); } } else { - await buildDefaultBabelConfig(options, config); + await buildDefaultBabelConfig(babelCore, options, config); } } -async function buildDefaultBabelConfig(options: PluginOptions, config: Config) { +async function buildDefaultBabelConfig( + babelCore: BabelCore, + options: PluginOptions, + config: Config, +) { // If this is a .ts or .tsx file, we don't need to enable flow. if (TYPESCRIPT_EXTNAME_RE.test(config.searchPath)) { return; diff --git a/packages/transformers/babel/src/env.js b/packages/transformers/babel/src/env.js deleted file mode 100644 index 8f25faadfb8..00000000000 --- a/packages/transformers/babel/src/env.js +++ /dev/null @@ -1,69 +0,0 @@ -// @flow strict-local - -import type {Config} from '@parcel/types'; -import presetEnv from '@babel/preset-env'; -import type {BabelConfig} from './types'; -import type {Targets as BabelTargets, PresetEnvPlugin} from '@babel/preset-env'; - -import getBabelTargets from './getBabelTargets'; -import {enginesToBabelTargets} from './utils'; - -/** - * Generates a @babel/preset-env config for an asset. - * This is done by finding the source module's target engines, and the app's - * target engines, and doing a diff to include only the necessary plugins. - */ -export default async function getEnvOptions( - config: Config, -): Promise { - // Only compile if there are engines defined in the environment. - if (Object.keys(config.env.engines).length === 0) { - return null; - } - - // Load the target engines for the app and generate a @babel/preset-env config - let appBabelTargets = enginesToBabelTargets(config.env); - - // If this is the app module, the source and target will be the same, so just compile everything. - // Otherwise, load the source engines and generate a babel-present-env config. - if (!config.isSource) { - let sourceBabelTargets = await getBabelTargets(config); - - if ( - !sourceBabelTargets || - !shouldCompileFurther(sourceBabelTargets, appBabelTargets) - ) { - return null; - } - } - - return { - targets: appBabelTargets, - config: {presets: ['@parcel/babel-preset-env']}, - }; -} - -function getNeededPlugins(targets: BabelTargets): Array { - return presetEnv( - {assertVersion: () => true}, - {targets: targets}, - ).plugins.filter(p => p[0]); -} - -function shouldCompileFurther( - sourceBabelTargets: BabelTargets, - appBabelTargets: BabelTargets, -): boolean { - let sourcePlugins = new Set(getNeededPlugins(sourceBabelTargets)); - let appPlugins = getNeededPlugins(appBabelTargets); - - // If there is any app plugin present that was not used to compile the source, - // then the asset was built to a higher target and will need to be compiled - // further - return appPlugins.some(plugin => { - return !sourcePlugins.has(plugin); - }); -} diff --git a/packages/transformers/babel/src/typescript.js b/packages/transformers/babel/src/typescript.js deleted file mode 100644 index 80d3e3c2b4e..00000000000 --- a/packages/transformers/babel/src/typescript.js +++ /dev/null @@ -1,25 +0,0 @@ -// @flow -import path from 'path'; - -import type {Config} from '@parcel/types'; -import type {BabelConfig} from './types'; - -export default function getTypescriptOptions( - config: Config, - pragma: ?string, - pragmaFrag: ?string, -): BabelConfig { - return { - plugins: [ - [ - '@babel/plugin-transform-typescript', - { - isTSX: path.extname(config.searchPath) === '.tsx', - // Needed because of https://github.com/babel/babel/issues/12585 - jsxPragma: pragma, - jsxPragmaFrag: pragmaFrag, - }, - ], - ], - }; -} diff --git a/yarn.lock b/yarn.lock index 5dbac28013f..7906735ac69 100644 --- a/yarn.lock +++ b/yarn.lock @@ -545,13 +545,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-typescript@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.12.13.tgz#9dff111ca64154cef0f4dc52cf843d9f12ce4474" - integrity sha512-cHP3u1JiUiG2LFDKbXnwVad81GvfyIOmCD6HIEId6ojrY0Drfy2q1jw7BwN7dE84+kTnBjLkXoL3IEy/3JPu2w== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - "@babel/plugin-transform-arrow-functions@^7.13.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" @@ -838,15 +831,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-typescript@^7.4.5": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.13.0.tgz#4a498e1f3600342d2a9e61f60131018f55774853" - integrity sha512-elQEwluzaU8R8dbVuW2Q2Y8Nznf7hnjM7+DSCd14Lo5fF63C9qNLbwZYbmZrtV9/ySpSUpkRpQXvJb6xyu4hCQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.13.0" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/plugin-syntax-typescript" "^7.12.13" - "@babel/plugin-transform-unicode-escapes@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74" From f572edb4ca3f7b7d4567327252a44918113f103b Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Tue, 11 May 2021 23:32:53 +0200 Subject: [PATCH 2/8] Use local require for `postcss` --- packages/transformers/postcss/package.json | 3 --- .../postcss/src/PostCSSTransformer.js | 22 +++++++++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/transformers/postcss/package.json b/packages/transformers/postcss/package.json index 2ca1e916005..a377c69902e 100644 --- a/packages/transformers/postcss/package.json +++ b/packages/transformers/postcss/package.json @@ -31,8 +31,5 @@ }, "devDependencies": { "postcss": "^8.2.1" - }, - "peerDependencies": { - "postcss": "^8.2.1" } } diff --git a/packages/transformers/postcss/src/PostCSSTransformer.js b/packages/transformers/postcss/src/PostCSSTransformer.js index a43ea49ebc0..bef0dd25c4a 100644 --- a/packages/transformers/postcss/src/PostCSSTransformer.js +++ b/packages/transformers/postcss/src/PostCSSTransformer.js @@ -1,6 +1,6 @@ // @flow -import type {FilePath, MutableAsset} from '@parcel/types'; +import type {FilePath, MutableAsset, PluginOptions} from '@parcel/types'; import {md5FromString} from '@parcel/utils'; import {Transformer} from '@parcel/plugin'; @@ -9,8 +9,8 @@ import nullthrows from 'nullthrows'; import path from 'path'; import semver from 'semver'; import valueParser from 'postcss-value-parser'; -import postcss from 'postcss'; import postcssModules from 'postcss-modules'; +import typeof * as Postcss from 'postcss'; import {load} from './loadConfig'; @@ -26,11 +26,13 @@ export default (new Transformer({ return ast.type === 'postcss' && semver.satisfies(ast.version, '^8.2.1'); }, - async parse({asset, config}) { + async parse({asset, config, options}) { if (!config) { return; } + const postcss = await loadPostcss(options, asset.filePath); + return { type: 'postcss', version: '8.2.1', @@ -48,6 +50,8 @@ export default (new Transformer({ return [asset]; } + const postcss: Postcss = await loadPostcss(options, asset.filePath); + let plugins = [...config.hydrated.plugins]; let cssModules: ?{|[string]: string|} = null; if (config.hydrated.modules) { @@ -149,7 +153,9 @@ export default (new Transformer({ return assets; }, - generate({ast}) { + async generate({asset, ast, options}) { + const postcss: Postcss = await loadPostcss(options, asset.filePath); + let code = ''; postcss.stringify(postcss.fromJSON(ast.program), c => { code += c; @@ -192,3 +198,11 @@ function createLoader( } }; } + +function loadPostcss(options: PluginOptions, from: FilePath): Promise { + return options.packageManager.require('postcss', from, { + range: '^8.2.1', + saveDev: true, + shouldAutoInstall: options.shouldAutoInstall, + }); +} From d24c7163810b8e292adb1be810fc7993d8bbefe9 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Wed, 12 May 2021 00:03:23 +0200 Subject: [PATCH 3/8] More permissive JSON parsing for Yarn/npm --- packages/core/package-manager/src/JSONParseStream.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/core/package-manager/src/JSONParseStream.js b/packages/core/package-manager/src/JSONParseStream.js index 497c1631d2b..0436d7a2b8e 100644 --- a/packages/core/package-manager/src/JSONParseStream.js +++ b/packages/core/package-manager/src/JSONParseStream.js @@ -17,7 +17,13 @@ export default class JSONParseStream extends Transform { callback: (err: ?Error, parsed: ?JSONObject) => mixed, ) { try { - callback(null, JSON.parse(chunk.toString())); + let parsed; + try { + parsed = JSON.parse(chunk.toString()); + } catch (e) { + return; + } + callback(null, parsed); } catch (err) { callback(err); } From c19436e43b9f94e35ff58e3677639b02f423457b Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Wed, 12 May 2021 01:16:27 +0200 Subject: [PATCH 4/8] Always use internal babel-core for default --- packages/transformers/babel/src/config.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/transformers/babel/src/config.js b/packages/transformers/babel/src/config.js index 90c781144c7..22e3362bd2e 100644 --- a/packages/transformers/babel/src/config.js +++ b/packages/transformers/babel/src/config.js @@ -56,7 +56,7 @@ export async function load( options.projectRoot, )) ) { - await buildDefaultBabelConfig(internalBabelCore, options, config); + await buildDefaultBabelConfig(options, config); return; } @@ -185,15 +185,11 @@ export async function load( config.setResultHash(md5FromObject(partialConfig.options)); } } else { - await buildDefaultBabelConfig(babelCore, options, config); + await buildDefaultBabelConfig(options, config); } } -async function buildDefaultBabelConfig( - babelCore: BabelCore, - options: PluginOptions, - config: Config, -) { +async function buildDefaultBabelConfig(options: PluginOptions, config: Config) { // If this is a .ts or .tsx file, we don't need to enable flow. if (TYPESCRIPT_EXTNAME_RE.test(config.searchPath)) { return; @@ -212,13 +208,13 @@ async function buildDefaultBabelConfig( } babelOptions.presets = (babelOptions.presets || []).map(preset => - babelCore.createConfigItem(preset, { + internalBabelCore.createConfigItem(preset, { type: 'preset', dirname: BABEL_TRANSFORMER_DIR, }), ); babelOptions.plugins = (babelOptions.plugins || []).map(plugin => - babelCore.createConfigItem(plugin, { + internalBabelCore.createConfigItem(plugin, { type: 'plugin', dirname: BABEL_TRANSFORMER_DIR, }), From 51f70f87855c1ef19c83d67af027b5be12e9c783 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Wed, 12 May 2021 10:11:20 +0200 Subject: [PATCH 5/8] Call addDevDependency --- packages/transformers/babel/src/config.js | 4 ++++ packages/transformers/postcss/src/loadConfig.js | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/packages/transformers/babel/src/config.js b/packages/transformers/babel/src/config.js index 22e3362bd2e..7cebeba058a 100644 --- a/packages/transformers/babel/src/config.js +++ b/packages/transformers/babel/src/config.js @@ -69,6 +69,10 @@ export async function load( shouldAutoInstall: options.shouldAutoInstall, }, ); + config.addDevDependency({ + moduleSpecifier: '@babel/core', + resolveFrom: config.searchPath, + }); let babelOptions = { filename: config.searchPath, diff --git a/packages/transformers/postcss/src/loadConfig.js b/packages/transformers/postcss/src/loadConfig.js index b6c98a5d882..d97bfaf526d 100644 --- a/packages/transformers/postcss/src/loadConfig.js +++ b/packages/transformers/postcss/src/loadConfig.js @@ -96,6 +96,11 @@ export async function load({ let contents = null; if (configFile) { + config.addDevDependency({ + moduleSpecifier: 'postcss', + resolveFrom: config.searchPath, + }); + contents = configFile.contents; let isDynamic = configFile && path.extname(configFile.filePath) === '.js'; if (isDynamic) { From 1eec4a80270eaa9e49e7ef80fb8f7497827e6d97 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Wed, 12 May 2021 23:04:41 +0200 Subject: [PATCH 6/8] Log parse JSONParseStream errors --- packages/core/package-manager/src/JSONParseStream.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/core/package-manager/src/JSONParseStream.js b/packages/core/package-manager/src/JSONParseStream.js index 0436d7a2b8e..34c8ef32ced 100644 --- a/packages/core/package-manager/src/JSONParseStream.js +++ b/packages/core/package-manager/src/JSONParseStream.js @@ -1,6 +1,8 @@ // @flow strict-local import type {JSONObject} from '@parcel/types'; + +import logger from '@parcel/logger'; import {Transform} from 'stream'; // Transforms chunks of json strings to parsed objects. @@ -21,6 +23,12 @@ export default class JSONParseStream extends Transform { try { parsed = JSON.parse(chunk.toString()); } catch (e) { + // Be permissive and ignoreJSON parse errors in case there was + // a non-JSON line in the package manager's stdout. + logger.verbose({ + message: 'Ignored invalid JSON message: ' + chunk.toString(), + origin: '@parcel/package-manager', + }); return; } callback(null, parsed); From 04b106ce256356fbd778fe2cd52d7f902c73c8ae Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Thu, 13 May 2021 11:47:08 +0200 Subject: [PATCH 7/8] Fix typo --- packages/transformers/babel/src/babel7.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/transformers/babel/src/babel7.js b/packages/transformers/babel/src/babel7.js index 5c34f6d72dd..9c89e68655f 100644 --- a/packages/transformers/babel/src/babel7.js +++ b/packages/transformers/babel/src/babel7.js @@ -17,7 +17,7 @@ export default async function babel7( babelOptions: any, additionalPlugins: Array = [], ): Promise { - const babelCode = babelOptions.internal + const babelCore = babelOptions.internal ? internalBabelCore : await options.packageManager.require('@babel/core', asset.filePath, { range: '^7.12.0', @@ -61,13 +61,13 @@ export default async function babel7( let ast = await asset.getAST(); let res; if (ast) { - res = await babelCode.transformFromAstAsync( + res = await babelCore.transformFromAstAsync( ast.program, asset.isASTDirty() ? undefined : await asset.getCode(), config, ); } else { - res = await babelCode.transformAsync(await asset.getCode(), config); + res = await babelCore.transformAsync(await asset.getCode(), config); } if (res.ast) { From d75c6edf9411e37bacd21e417a38ceb0c762ae7e Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Thu, 13 May 2021 13:36:51 +0200 Subject: [PATCH 8/8] Fixup --- packages/core/integration-tests/test/transpilation.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/integration-tests/test/transpilation.js b/packages/core/integration-tests/test/transpilation.js index 574fd5b04e3..18191f68c29 100644 --- a/packages/core/integration-tests/test/transpilation.js +++ b/packages/core/integration-tests/test/transpilation.js @@ -148,7 +148,6 @@ describe('transpilation', function() { ); let file = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); - console.log(file); assert(file.includes('React.createElement("div"')); assert(file.includes('...a')); assert(!file.includes('@swc/helpers'));