From f23c844c10e63549322f2fd2180a6e8a464b9ceb Mon Sep 17 00:00:00 2001 From: Lyubomir Date: Fri, 8 Feb 2019 20:09:25 +0100 Subject: [PATCH] Enables jsx plugin in case jsx syntax is used in js files (#2530) * Enables jsx plugin in case jsx syntax is used in js files * Consider pragma when enabling JSX in .js files * Add tests for JSX support in JS even if no dependencies are specified * Make comment more clear * Cache regex creation --- .../integration/jsx-hyperapp-no-dep/index.js | 3 + .../jsx-hyperapp-no-dep/package.json | 3 + .../integration/jsx-nervjs-no-dep/index.js | 3 + .../jsx-nervjs-no-dep/package.json | 3 + .../integration/jsx-preact-no-dep/index.js | 3 + .../jsx-preact-no-dep/package.json | 3 + .../integration/jsx-react-no-dep/index.js | 3 + .../integration/jsx-react-no-dep/package.json | 3 + .../core/integration-tests/test/javascript.js | 89 +++++++++++++++++++ .../src/transforms/babel/jsx.js | 32 +++++++ 10 files changed, 145 insertions(+) create mode 100644 packages/core/integration-tests/test/integration/jsx-hyperapp-no-dep/index.js create mode 100644 packages/core/integration-tests/test/integration/jsx-hyperapp-no-dep/package.json create mode 100644 packages/core/integration-tests/test/integration/jsx-nervjs-no-dep/index.js create mode 100644 packages/core/integration-tests/test/integration/jsx-nervjs-no-dep/package.json create mode 100644 packages/core/integration-tests/test/integration/jsx-preact-no-dep/index.js create mode 100644 packages/core/integration-tests/test/integration/jsx-preact-no-dep/package.json create mode 100644 packages/core/integration-tests/test/integration/jsx-react-no-dep/index.js create mode 100644 packages/core/integration-tests/test/integration/jsx-react-no-dep/package.json diff --git a/packages/core/integration-tests/test/integration/jsx-hyperapp-no-dep/index.js b/packages/core/integration-tests/test/integration/jsx-hyperapp-no-dep/index.js new file mode 100644 index 00000000000..4a97bbe9739 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-hyperapp-no-dep/index.js @@ -0,0 +1,3 @@ +import * as Hyperapp from 'hyperapp' + +module.exports =
; diff --git a/packages/core/integration-tests/test/integration/jsx-hyperapp-no-dep/package.json b/packages/core/integration-tests/test/integration/jsx-hyperapp-no-dep/package.json new file mode 100644 index 00000000000..352055cdf83 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-hyperapp-no-dep/package.json @@ -0,0 +1,3 @@ +{ + "private": true +} diff --git a/packages/core/integration-tests/test/integration/jsx-nervjs-no-dep/index.js b/packages/core/integration-tests/test/integration/jsx-nervjs-no-dep/index.js new file mode 100644 index 00000000000..9c8f2c81f29 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-nervjs-no-dep/index.js @@ -0,0 +1,3 @@ +import * as Nerv from 'nervjs'; + +module.exports =
; diff --git a/packages/core/integration-tests/test/integration/jsx-nervjs-no-dep/package.json b/packages/core/integration-tests/test/integration/jsx-nervjs-no-dep/package.json new file mode 100644 index 00000000000..352055cdf83 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-nervjs-no-dep/package.json @@ -0,0 +1,3 @@ +{ + "private": true +} diff --git a/packages/core/integration-tests/test/integration/jsx-preact-no-dep/index.js b/packages/core/integration-tests/test/integration/jsx-preact-no-dep/index.js new file mode 100644 index 00000000000..9483f2ef3e4 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-preact-no-dep/index.js @@ -0,0 +1,3 @@ +const Preact = require('preact'); + +module.exports =
; diff --git a/packages/core/integration-tests/test/integration/jsx-preact-no-dep/package.json b/packages/core/integration-tests/test/integration/jsx-preact-no-dep/package.json new file mode 100644 index 00000000000..352055cdf83 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-preact-no-dep/package.json @@ -0,0 +1,3 @@ +{ + "private": true +} diff --git a/packages/core/integration-tests/test/integration/jsx-react-no-dep/index.js b/packages/core/integration-tests/test/integration/jsx-react-no-dep/index.js new file mode 100644 index 00000000000..4f5a71615ed --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-react-no-dep/index.js @@ -0,0 +1,3 @@ +import * as React from 'react'; + +module.exports =
; diff --git a/packages/core/integration-tests/test/integration/jsx-react-no-dep/package.json b/packages/core/integration-tests/test/integration/jsx-react-no-dep/package.json new file mode 100644 index 00000000000..352055cdf83 --- /dev/null +++ b/packages/core/integration-tests/test/integration/jsx-react-no-dep/package.json @@ -0,0 +1,3 @@ +{ + "private": true +} diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index c481b081df5..a8b1fdd6c8a 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -1390,6 +1390,28 @@ describe('javascript', function() { assert(file.includes('React.createElement("div"')); }); + it('should support compiling JSX in JS files with React dependency even if React is not specified as dependency', async function() { + let originalPkg = await fs.readFile( + __dirname + '/integration/jsx-react-no-dep/package.json' + ); + + await bundle( + path.join(__dirname, '/integration/jsx-react-no-dep/index.js') + ); + + let file = await fs.readFile( + path.join(__dirname, '/dist/index.js'), + 'utf8' + ); + + assert(file.includes('React.createElement("div"')); + + await fs.writeFile( + __dirname + '/integration/jsx-react-no-dep/package.json', + originalPkg + ); + }); + it('should support compiling JSX in JS files with Preact dependency', async function() { await bundle(path.join(__dirname, '/integration/jsx-preact/index.js')); @@ -1400,6 +1422,28 @@ describe('javascript', function() { assert(file.includes('h("div"')); }); + it('should support compiling JSX in JS files with Preact dependency even if Preact is not specified as dependency', async function() { + let originalPkg = await fs.readFile( + __dirname + '/integration/jsx-preact-no-dep/package.json' + ); + + await bundle( + path.join(__dirname, '/integration/jsx-preact-no-dep/index.js') + ); + + let file = await fs.readFile( + path.join(__dirname, '/dist/index.js'), + 'utf8' + ); + + assert(file.includes('h("div"')); + + await fs.writeFile( + __dirname + '/integration/jsx-preact-no-dep/package.json', + originalPkg + ); + }); + it('should support compiling JSX in JS files with Nerv dependency', async function() { await bundle(path.join(__dirname, '/integration/jsx-nervjs/index.js')); @@ -1410,6 +1454,28 @@ describe('javascript', function() { assert(file.includes('Nerv.createElement("div"')); }); + it('should support compiling JSX in JS files with Nerv dependency even if Nerv is not specified as dependency', async function() { + let originalPkg = await fs.readFile( + __dirname + '/integration/jsx-nervjs-no-dep/package.json' + ); + + await bundle( + path.join(__dirname, '/integration/jsx-nervjs-no-dep/index.js') + ); + + let file = await fs.readFile( + path.join(__dirname, '/dist/index.js'), + 'utf8' + ); + + assert(file.includes('Nerv.createElement("div"')); + + await fs.writeFile( + __dirname + '/integration/jsx-nervjs-no-dep/package.json', + originalPkg + ); + }); + it('should support compiling JSX in JS files with Hyperapp dependency', async function() { await bundle(path.join(__dirname, '/integration/jsx-hyperapp/index.js')); @@ -1417,7 +1483,30 @@ describe('javascript', function() { path.join(__dirname, '/dist/index.js'), 'utf8' ); + + assert(file.includes('h("div"')); + }); + + it('should support compiling JSX in JS files with Hyperapp dependency even if Hyperapp is not specified as dependency', async function() { + let originalPkg = await fs.readFile( + __dirname + '/integration/jsx-hyperapp-no-dep/package.json' + ); + + await bundle( + path.join(__dirname, '/integration/jsx-hyperapp-no-dep/index.js') + ); + + let file = await fs.readFile( + path.join(__dirname, '/dist/index.js'), + 'utf8' + ); + assert(file.includes('h("div"')); + + await fs.writeFile( + __dirname + '/integration/jsx-hyperapp-no-dep/package.json', + originalPkg + ); }); it('should support optional dependencies in try...catch blocks', async function() { diff --git a/packages/core/parcel-bundler/src/transforms/babel/jsx.js b/packages/core/parcel-bundler/src/transforms/babel/jsx.js index de4ceb70210..48e37d1c45e 100644 --- a/packages/core/parcel-bundler/src/transforms/babel/jsx.js +++ b/packages/core/parcel-bundler/src/transforms/babel/jsx.js @@ -12,6 +12,34 @@ const JSX_PRAGMA = { hyperapp: 'h' }; +function createJSXRegexFor(dependency) { + // result looks like /from\s+[`"']react[`"']|require\([`"']react[`"']\)/ + return new RegExp( + `from\\s+[\`"']${dependency}[\`"']|require\\([\`"']${dependency}[\`"']\\)` + ); +} + +/** + * Solves a use case when JSX is used in .js files, but + * package.json is empty or missing yet and therefore pragma cannot + * be determined based on pkg.dependencies / pkg.devDependencies + */ +const cacheJsxRegexFor = {}; +function maybeCreateFallbackPragma(asset) { + for (const dep in JSX_PRAGMA) { + let regex = cacheJsxRegexFor[dep]; + + if (!regex) { + regex = createJSXRegexFor(dep); + cacheJsxRegexFor[dep] = regex; + } + + if (asset.contents.match(regex)) { + return JSX_PRAGMA[dep]; + } + } +} + /** * Generates a babel config for JSX. Attempts to detect react or react-like libraries * and changes the pragma accordingly. @@ -37,6 +65,10 @@ async function getJSXConfig(asset, isSourceModule) { } } + if (!pragma) { + pragma = maybeCreateFallbackPragma(asset); + } + if (pragma || JSX_EXTENSIONS[path.extname(asset.name)]) { return { internal: true,