-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Various updates to Babel 7 branch #1958
Changes from 20 commits
05c0fb8
89d236b
4e613c9
106c43d
71a75dc
dd06677
cfad048
a1b0f4c
bbf0cd4
04617c4
03c88b5
3acd84a
4af249a
b371872
ad78546
682175c
8bdb5b3
15a1421
762cc00
74ab5f7
b0fa467
2173572
16d9fa7
112ebf3
0dd2663
367d5ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,8 @@ | ||
{ | ||
"presets": [["env", { | ||
"presets": [["@babel/preset-env", { | ||
"targets": { | ||
"node": "6" | ||
} | ||
}]], | ||
"plugins": ["transform-async-super"], | ||
"ignore": ["builtins"] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -225,12 +225,11 @@ class JSPackager extends Packager { | |
// Add source map url if a map bundle exists | ||
let mapBundle = this.bundle.siblingBundlesMap.get('map'); | ||
if (mapBundle) { | ||
await this.write( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discovered a potential bug with template strings in Babel 7. But I think it has already been reported. Feel free to check if anyone is up for it :) It might have been an issue in the babel config I wrote, not sure. |
||
`\n//# sourceMappingURL=${urlJoin( | ||
this.options.publicURL, | ||
path.basename(mapBundle.name) | ||
)}` | ||
let mapUrl = urlJoin( | ||
this.options.publicURL, | ||
path.basename(mapBundle.name) | ||
); | ||
await this.write(`\n//# sourceMappingURL=${mapUrl}`); | ||
} | ||
} | ||
await this.dest.end(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -100,6 +100,15 @@ async function getBabelConfig(asset) { | |
|
||
// Try to resolve a .babelrc file. If one is found, consider the module source code. | ||
let babelrc = await getBabelRc(asset, isSource); | ||
let isBabel7 = true; | ||
if (babelrc) { | ||
isBabel7 = babelrc.version === 7; | ||
babelrc = babelrc.config; | ||
|
||
if (!isBabel7) { | ||
console.log('Found a babel 6 module in: ', asset.name); | ||
} | ||
} | ||
isSource = isSource || !!babelrc; | ||
|
||
let envConfig = await getEnvConfig(asset, isSource); | ||
|
@@ -129,15 +138,21 @@ async function getBabelConfig(asset) { | |
|
||
// Add JSX config if it isn't already specified in the babelrc | ||
let hasReact = | ||
hasPlugin(babelrc.presets, 'react') || | ||
hasPlugin(babelrc.plugins, 'transform-react-jsx'); | ||
hasPlugin(babelrc.presets, ['react', '@babel/preset-react']) || | ||
hasPlugin(babelrc.plugins, [ | ||
'transform-react-jsx', | ||
'@babel/plugin-transform-react-jsx' | ||
]); | ||
|
||
if (!hasReact) { | ||
mergeConfigs(babelrc, jsxConfig); | ||
} | ||
|
||
// Add Flow stripping config if it isn't already specified in the babelrc | ||
let hasFlow = hasPlugin(babelrc.plugins, 'transform-flow-strip-types'); | ||
let hasFlow = hasPlugin(babelrc.plugins, [ | ||
'transform-flow-strip-types', | ||
'@babel/plugin-transform-flow-strip-types' | ||
]); | ||
|
||
if (!hasFlow && flowConfig) { | ||
mergeConfigs(babelrc, flowConfig); | ||
|
@@ -177,21 +192,49 @@ function mergeConfigs(a, b) { | |
return a; | ||
} | ||
|
||
function hasPlugin(arr, plugin) { | ||
return Array.isArray(arr) && arr.some(p => getPluginName(p) === plugin); | ||
function hasPlugin(arr, plugins) { | ||
return ( | ||
Array.isArray(arr) && arr.some(p => plugins.includes(getPluginName(p))) | ||
); | ||
} | ||
|
||
function getPluginName(p) { | ||
return Array.isArray(p) ? p[0] : p; | ||
} | ||
|
||
function testPluginArrayForBabelScope(plugins) { | ||
for (let plugin of plugins) { | ||
if (getPluginName(plugin).startsWith('@babel/')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does babel 7 require the scope or will they automatically add it if you just write There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Babel docs:
So yes it's required, although it's not 100% reliable as third party libraries will still have babel-.... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
function isBabel7Config(babelrc) { | ||
if (!babelrc.presets && !babelrc.presets) { | ||
return true; | ||
} | ||
|
||
if ( | ||
(babelrc.presets && testPluginArrayForBabelScope(babelrc.presets)) || | ||
(babelrc.plugins && testPluginArrayForBabelScope(babelrc.plugins)) | ||
) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Finds a .babelrc for an asset. By default, .babelrc files inside node_modules are not used. | ||
* However, there are some exceptions: | ||
* - if `browserify.transforms` includes "babelify" in package.json (for legacy module compat) | ||
* - the `source` field in package.json is used by the resolver | ||
*/ | ||
async function getBabelRc(asset, isSource) { | ||
let babelrc = null; | ||
|
||
// Support legacy browserify packages | ||
let pkg = await asset.getPackage(); | ||
let browserify = pkg && pkg.browserify; | ||
|
@@ -203,21 +246,28 @@ async function getBabelRc(asset, isSource) { | |
|
||
// If specified as an array, override the config with the one specified | ||
if (Array.isArray(babelify) && babelify[1]) { | ||
return babelify[1]; | ||
babelrc = babelify[1]; | ||
} | ||
|
||
// Otherwise, return the .babelrc if babelify was found | ||
return babelify ? await findBabelRc(asset) : null; | ||
if (!babelrc && babelify) { | ||
babelrc = await findBabelRc(asset); | ||
} | ||
} | ||
|
||
// If this asset is not in node_modules, always use the .babelrc | ||
if (isSource) { | ||
return await findBabelRc(asset); | ||
if (!babelrc && isSource) { | ||
babelrc = await findBabelRc(asset); | ||
} | ||
|
||
// Otherwise, don't load .babelrc for node_modules. | ||
// See https://github.com/parcel-bundler/parcel/issues/13. | ||
return null; | ||
return babelrc | ||
? { | ||
version: isBabel7Config(babelrc) ? 7 : 6, | ||
config: babelrc | ||
} | ||
: null; | ||
} | ||
|
||
async function findBabelRc(asset) { | ||
|
@@ -226,15 +276,16 @@ async function findBabelRc(asset) { | |
}); | ||
} | ||
|
||
function shouldIgnoreBabelrc(filename, babelrc) { | ||
return false; | ||
/*function shouldIgnoreBabelrc(filename, babelrc) { | ||
// Determine if we should ignore this babelrc file. We do this here instead of | ||
// letting @babel/core handle it because this config might be merged with our | ||
// autogenerated one later which shouldn't be ignored. | ||
// let ignore = babelUtils.arrayify(babelrc.ignore, babelUtils.regexify); | ||
// let only = | ||
// babelrc.only && babelUtils.arrayify(babelrc.only, babelUtils.regexify); | ||
// return babelUtils.shouldIgnore(filename, ignore, only); | ||
let ignore = babelUtils.arrayify(babelrc.ignore, babelUtils.regexify); | ||
let only = babelrc.only && babelUtils.arrayify(babelrc.only, babelUtils.regexify); | ||
return babelUtils.shouldIgnore(filename, ignore, only); | ||
}*/ | ||
function shouldIgnoreBabelrc() { | ||
return false; | ||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
const traverse = require('@babel/traverse').default; | ||
|
||
// Convert between babel 7 and babel 6 AST | ||
// More info on the AST Changes: https://babeljs.io/docs/en/v7-migration-api#ast-changes | ||
function babel7toBabel6(ast) { | ||
const visitor = { | ||
ArrowFunctionExpression: node => { | ||
node.expression = node.body.type !== 'BlockStatement'; | ||
}, | ||
ExistsTypeAnnotation: node => { | ||
node.type = 'ExistentialTypeParam'; | ||
}, | ||
NumberLiteralTypeAnnotation: node => { | ||
node.type = 'NumericLiteralTypeAnnotation'; | ||
}, | ||
ObjectTypeIndexer: node => { | ||
node.end++; | ||
node.loc.end.column++; | ||
}, | ||
ForOfStatement: node => { | ||
node.type = 'ForAwaitStatement'; | ||
delete node.await; | ||
}, | ||
SpreadElement: (node, path) => { | ||
if ( | ||
path.parentPath.isObjectExpression() || | ||
path.parentPath.isArrayExpression() | ||
) { | ||
node.type = 'SpreadProperty'; | ||
} | ||
}, | ||
RestElement: (node, path) => { | ||
if ( | ||
path.parentPath.isObjectPattern() || | ||
path.parentPath.isArrayPattern() | ||
) { | ||
node.type = 'RestProperty'; | ||
} | ||
} | ||
}; | ||
|
||
traverse(ast, { | ||
enter(path) { | ||
if (path.node.variance && path.node.variance.type === 'Variance') { | ||
path.node.variance = path.node.variance.kind; | ||
} | ||
|
||
let visitorFunc = visitor[path.node.type]; | ||
if (visitorFunc) { | ||
visitorFunc(path.node, path); | ||
} | ||
} | ||
}); | ||
|
||
return ast; | ||
} | ||
|
||
function babel6toBabel7(ast) { | ||
const visitor = { | ||
ArrowFunctionExpression: node => { | ||
delete node.expression; | ||
}, | ||
ExistentialTypeParam: node => { | ||
node.type = 'ExistsTypeAnnotation'; | ||
}, | ||
NumericLiteralTypeAnnotation: node => { | ||
node.type = 'NumberLiteralTypeAnnotation'; | ||
}, | ||
ObjectTypeIndexer: node => { | ||
node.end--; | ||
node.loc.end.column--; | ||
}, | ||
ForAwaitStatement: node => { | ||
node.type = 'ForOfStatement'; | ||
node.await = true; | ||
}, | ||
SpreadProperty: node => { | ||
node.type = 'SpreadElement'; | ||
}, | ||
RestProperty: node => { | ||
node.type = 'RestElement'; | ||
} | ||
}; | ||
|
||
traverse(ast, { | ||
enter(path) { | ||
if (path.node.variance && typeof path.node.variance === 'string') { | ||
path.node.variance = { | ||
type: 'VarianceNode', | ||
kind: path.node.variance | ||
}; | ||
} | ||
|
||
let visitorFunc = visitor[path.node.type]; | ||
if (visitorFunc) { | ||
visitorFunc(path.node); | ||
} | ||
} | ||
}); | ||
|
||
return ast; | ||
} | ||
|
||
module.exports = function(ast, version) { | ||
if (![6, 7].includes(version)) { | ||
throw new Error('This convertor only supports Babel 6 and 7 ASTs'); | ||
} | ||
|
||
return version === 7 ? babel7toBabel6(ast) : babel6toBabel7(ast); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we remove this, or do a PR to their branch to update to
@babel/types
instead ofbabel-types
It might cause issues in certain cases, as babel-types has changed slightly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
worth doing some perf testing. babylon-walk was WAY faster than babel-traverse for some cases where we don't need scope tracking and things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure it will still be slower, haven't tested it. I did however open up a PR to babylon-walk pugjs/babel-walk#2