fix tsx+jsx error (#916)
* fix tsx+jsx error * throw error if no build can be returned
This commit is contained in:
parent
189098b6e5
commit
829d5baafe
14 changed files with 91 additions and 19 deletions
5
.changeset/heavy-ears-hope.md
Normal file
5
.changeset/heavy-ears-hope.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Fix TSX issue with JSX multi-rendering
|
|
@ -23,6 +23,10 @@ function getLoader(fileExt) {
|
|||
return fileExt.substr(1);
|
||||
}
|
||||
|
||||
// The `tsx` loader in esbuild will remove unused imports, so we need to
|
||||
// be careful about esbuild not treating h, React, Fragment, etc. as unused.
|
||||
const PREVENT_UNUSED_IMPORTS = ';;(React,Fragment,h);';
|
||||
|
||||
/**
|
||||
* @type {import('snowpack').SnowpackPluginFactory<PluginOptions>}
|
||||
*/
|
||||
|
@ -74,18 +78,8 @@ module.exports = function jsxPlugin(config, options = {}) {
|
|||
};
|
||||
|
||||
if (importSources.size === 0) {
|
||||
error(
|
||||
logging,
|
||||
'renderer',
|
||||
`${colors.yellow(filePath)}
|
||||
Unable to resolve a renderer that handles JSX transforms! Please include a \`renderer\` plugin which supports JSX in your \`astro.config.mjs\` file.`
|
||||
);
|
||||
|
||||
return {
|
||||
'.js': {
|
||||
code: '',
|
||||
},
|
||||
};
|
||||
throw new Error(`${colors.yellow(filePath)}
|
||||
Unable to resolve a renderer that handles JSX transforms! Please include a \`renderer\` plugin which supports JSX in your \`astro.config.mjs\` file.`);
|
||||
}
|
||||
|
||||
// If we only have a single renderer, we can skip a bunch of work!
|
||||
|
@ -99,10 +93,10 @@ Unable to resolve a renderer that handles JSX transforms! Please include a \`ren
|
|||
};
|
||||
}
|
||||
|
||||
// we need valid JS to scan for imports
|
||||
// so let's just use `h` and `Fragment` as placeholders
|
||||
const { code: codeToScan } = await esbuild.transform(code, {
|
||||
loader: 'jsx',
|
||||
// we need valid JS here, so we can use `h` and `Fragment` as placeholders
|
||||
// NOTE(fks, matthewp): Make sure that you're transforming the original contents here.
|
||||
const { code: codeToScan } = await esbuild.transform(contents + PREVENT_UNUSED_IMPORTS, {
|
||||
loader,
|
||||
jsx: 'transform',
|
||||
jsxFactory: 'h',
|
||||
jsxFragment: 'Fragment',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/** @jsxImportSource preact */
|
||||
|
||||
export default function() {
|
||||
return <div id="pragma-comment">Hello world</div>;
|
||||
return <div class="pragma-comment">Hello world</div>;
|
||||
}
|
||||
|
|
5
packages/astro/test/fixtures/preact-component/src/components/PragmaCommentTypeScript.tsx
vendored
Normal file
5
packages/astro/test/fixtures/preact-component/src/components/PragmaCommentTypeScript.tsx
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/** @jsxImportSource preact */
|
||||
|
||||
export default function({}: object) {
|
||||
return <div class="pragma-comment">Hello world</div>;
|
||||
}
|
5
packages/astro/test/fixtures/preact-component/src/components/TypeScriptComponent.tsx
vendored
Normal file
5
packages/astro/test/fixtures/preact-component/src/components/TypeScriptComponent.tsx
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
import {h} from 'preact';
|
||||
|
||||
export default function({}: object) {
|
||||
return <div class="ts-component">Hello world</div>;
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
---
|
||||
import PragmaComponent from '../components/PragmaComment.jsx';
|
||||
import PragmaComponentTypeScript from '../components/PragmaCommentTypeScript.tsx';
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Preact component works with Pragma comment</title>
|
||||
</head>
|
||||
<body><PragmaComponent client:load/></body>
|
||||
<body>
|
||||
<PragmaComponent client:load/>
|
||||
<PragmaComponentTypeScript client:load/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
12
packages/astro/test/fixtures/preact-component/src/pages/ts-components.astro
vendored
Normal file
12
packages/astro/test/fixtures/preact-component/src/pages/ts-components.astro
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
import TypeScriptComponent from '../components/TypeScriptComponent.tsx';
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Preact TS component</title>
|
||||
</head>
|
||||
<body>
|
||||
<TypeScriptComponent client:load />
|
||||
</body>
|
||||
</html>
|
5
packages/astro/test/fixtures/react-component/src/components/PragmaComment.jsx
vendored
Normal file
5
packages/astro/test/fixtures/react-component/src/components/PragmaComment.jsx
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/** @jsxImportSource react */
|
||||
|
||||
export default function() {
|
||||
return <div className="pragma-comment">Hello world</div>;
|
||||
}
|
5
packages/astro/test/fixtures/react-component/src/components/PragmaCommentTypeScript.tsx
vendored
Normal file
5
packages/astro/test/fixtures/react-component/src/components/PragmaCommentTypeScript.tsx
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/** @jsxImportSource react */
|
||||
|
||||
export default function({}: object) {
|
||||
return <div className="pragma-comment">Hello world</div>;
|
||||
}
|
5
packages/astro/test/fixtures/react-component/src/components/TypeScriptComponent.tsx
vendored
Normal file
5
packages/astro/test/fixtures/react-component/src/components/TypeScriptComponent.tsx
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function({}) {
|
||||
return <div className="ts-component">Hello world</div>;
|
||||
}
|
|
@ -4,6 +4,7 @@ import Later from '../components/Goodbye.vue'; // use different specifier
|
|||
import ArrowFunction from '../components/ArrowFunction.jsx';
|
||||
import PropsSpread from '../components/PropsSpread.jsx';
|
||||
import {Research2} from '../components/Research.jsx';
|
||||
import TypeScriptComponent from '../components/TypeScriptComponent';
|
||||
|
||||
const someProps = {
|
||||
text: 'Hello world!',
|
||||
|
@ -20,5 +21,6 @@ const someProps = {
|
|||
<ArrowFunction />
|
||||
<PropsSpread {...someProps}/>
|
||||
<Research2 client:idle />
|
||||
<TypeScriptComponent client:load />
|
||||
</body>
|
||||
</html>
|
||||
|
|
14
packages/astro/test/fixtures/react-component/src/pages/pragma-comment.astro
vendored
Normal file
14
packages/astro/test/fixtures/react-component/src/pages/pragma-comment.astro
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
import PragmaComponent from '../components/PragmaComment.jsx';
|
||||
import PragmaComponentTypeScript from '../components/PragmaCommentTypeScript.tsx';
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>React component works with Pragma comment</title>
|
||||
</head>
|
||||
<body>
|
||||
<PragmaComponent client:load/>
|
||||
<PragmaComponentTypeScript client:load/>
|
||||
</body>
|
||||
</html>
|
|
@ -25,6 +25,14 @@ PreactComponent('Can load function component', async ({ runtime }) => {
|
|||
assert.equal($('#arrow-fn-component').length, 1, 'Can use function components');
|
||||
});
|
||||
|
||||
PreactComponent('Can load TS component', async ({ runtime }) => {
|
||||
const result = await runtime.load('/ts-components');
|
||||
assert.ok(!result.error, `build error: ${result.error}`);
|
||||
const $ = doc(result.contents);
|
||||
assert.equal($('.ts-component').length, 1, 'Can use TS components');
|
||||
});
|
||||
|
||||
|
||||
PreactComponent('Can use hooks', async ({ runtime }) => {
|
||||
const result = await runtime.load('/hooks');
|
||||
assert.ok(!result.error, `build error: ${result.error}`);
|
||||
|
@ -46,7 +54,7 @@ PreactComponent('Can use a pragma comment', async ({ runtime }) => {
|
|||
assert.ok(!result.error, `build error: ${result.error}`);
|
||||
|
||||
const $ = doc(result.contents);
|
||||
assert.equal($('#pragma-comment').length, 1, 'rendered the PragmaComment component.');
|
||||
assert.equal($('.pragma-comment').length, 2, 'rendered the PragmaComment component.');
|
||||
});
|
||||
|
||||
PreactComponent('Uses the new JSX transform', async ({ runtime }) => {
|
||||
|
|
|
@ -43,6 +43,7 @@ React('Can load React', async () => {
|
|||
assert.equal($('#arrow-fn-component').length, 1, 'Can use function components');
|
||||
assert.equal($('#component-spread-props').length, 1, 'Can use spread for components');
|
||||
assert.equal($('#component-spread-props').text(), 'Hello world!');
|
||||
assert.equal($('.ts-component').length, 1, 'Can use TS components');
|
||||
});
|
||||
|
||||
React('Includes reactroot on hydrating components', async () => {
|
||||
|
@ -74,6 +75,13 @@ React('Can load Vue', async () => {
|
|||
assert.equal($('#vue-h2').text(), 'Hasta la vista, baby');
|
||||
});
|
||||
|
||||
React('Can use a pragma comment', async () => {
|
||||
const result = await runtime.load('/pragma-comment');
|
||||
assert.ok(!result.error, `build error: ${result.error}`);
|
||||
const $ = doc(result.contents);
|
||||
assert.equal($('.pragma-comment').length, 2, 'rendered the PragmaComment component.');
|
||||
});
|
||||
|
||||
React('uses the new JSX transform', async () => {
|
||||
const result = await runtime.load('/');
|
||||
assert.ok(!result.error, `build error: ${result.error}`);
|
||||
|
|
Loading…
Reference in a new issue