fix(react): generate valid Vite + JSX setup for React (#27130)
The current `@nx/react:app` generator does not take the `--js` option into account. There are two problems: 1. `index.html` includes `main.tsx` not `main.jsx`. 2. `.js` files with JSX are invalid in Vite, and must be named `.jsx`. This PR adds a new option to the `toJS` devkit util to preserve `.jsx` rather than renaming them to `.js`. The vast majority of non-Vite React projects will use `.js` and not `.jsx` (e.g. Next.js, Expo, Remix, etc.) so we just want to apply this change to Vite only for now. In the future we could enhance React generators to support `--jsx`, for example. ## Current Behavior <!-- This is the behavior we have today --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #20810
This commit is contained in:
parent
d2e3fc79db
commit
45c458e677
@ -4,8 +4,9 @@
|
||||
|
||||
#### Type declaration
|
||||
|
||||
| Name | Type |
|
||||
| :---------- | :------------------------------ |
|
||||
| `extension` | `".js"` \| `".mjs"` \| `".cjs"` |
|
||||
| `module?` | `ModuleKind` |
|
||||
| `target?` | `ScriptTarget` |
|
||||
| Name | Type |
|
||||
| :----------- | :------------------------------ |
|
||||
| `extension?` | `".js"` \| `".mjs"` \| `".cjs"` |
|
||||
| `module?` | `ModuleKind` |
|
||||
| `target?` | `ScriptTarget` |
|
||||
| `useJsx?` | `boolean` |
|
||||
|
||||
45
packages/devkit/src/generators/to-js.spec.ts
Normal file
45
packages/devkit/src/generators/to-js.spec.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { createTree } from 'nx/src/generators/testing-utils/create-tree';
|
||||
import type { Tree } from 'nx/src/generators/tree';
|
||||
|
||||
import { toJS } from './to-js';
|
||||
|
||||
describe('toJS', () => {
|
||||
let tree: Tree;
|
||||
beforeEach(() => {
|
||||
tree = createTree();
|
||||
});
|
||||
|
||||
it('should renamed .ts and .tsx file to .js', () => {
|
||||
tree.write('a.ts', '// a');
|
||||
tree.write('b.tsx', '// b');
|
||||
|
||||
toJS(tree);
|
||||
|
||||
expect(tree.exists('a.ts')).toBeFalsy();
|
||||
expect(tree.exists('b.tsx')).toBeFalsy();
|
||||
expect(tree.read('a.js', 'utf-8')).toContain('// a');
|
||||
expect(tree.read('b.js', 'utf-8')).toContain('// b');
|
||||
});
|
||||
|
||||
it('should support different extensions', () => {
|
||||
tree.write('a.ts', '// a');
|
||||
|
||||
toJS(tree, {
|
||||
extension: '.mjs',
|
||||
});
|
||||
|
||||
expect(tree.read('a.mjs', 'utf-8')).toContain('// a');
|
||||
});
|
||||
|
||||
it('should support .jsx rather than .js files (for Vite)', () => {
|
||||
tree.write('a.ts', '// a');
|
||||
tree.write('b.tsx', '// b');
|
||||
|
||||
toJS(tree, {
|
||||
useJsx: true,
|
||||
});
|
||||
|
||||
expect(tree.read('a.js', 'utf-8')).toContain('// a');
|
||||
expect(tree.read('b.jsx', 'utf-8')).toContain('// b');
|
||||
});
|
||||
});
|
||||
@ -1,12 +1,13 @@
|
||||
import type { Tree } from 'nx/src/devkit-exports';
|
||||
import type { ScriptTarget, ModuleKind } from 'typescript';
|
||||
import type { ModuleKind, ScriptTarget } from 'typescript';
|
||||
import { typescriptVersion } from '../utils/versions';
|
||||
import { ensurePackage } from '../utils/package-json';
|
||||
|
||||
export type ToJSOptions = {
|
||||
target?: ScriptTarget;
|
||||
extension?: '.js' | '.mjs' | '.cjs';
|
||||
module?: ModuleKind;
|
||||
extension: '.js' | '.mjs' | '.cjs';
|
||||
target?: ScriptTarget;
|
||||
useJsx?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -32,10 +33,15 @@ export function toJS(tree: Tree, options?: ToJSOptions): void {
|
||||
module: options?.module ?? ModuleKind.ESNext,
|
||||
})
|
||||
);
|
||||
tree.rename(
|
||||
c.path,
|
||||
c.path.replace(/\.tsx?$/, options?.extension ?? '.js')
|
||||
);
|
||||
tree.rename(c.path, c.path.replace(/\.ts$/, options?.extension ?? '.js'));
|
||||
if (options?.useJsx) {
|
||||
tree.rename(c.path, c.path.replace(/\.tsx$/, '.jsx'));
|
||||
} else {
|
||||
tree.rename(
|
||||
c.path,
|
||||
c.path.replace(/\.tsx$/, options?.extension ?? '.js')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,6 +399,19 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
expect(appTree.read('my-app/vite.config.ts', 'utf-8')).toMatchSnapshot();
|
||||
expect(appTree.read('my-app/index.html', 'utf-8')).toContain('main.tsx');
|
||||
});
|
||||
|
||||
it('should setup vite if bundler is vite (--js)', async () => {
|
||||
await applicationGenerator(appTree, {
|
||||
...schema,
|
||||
name: 'my-app',
|
||||
bundler: 'vite',
|
||||
js: true,
|
||||
});
|
||||
|
||||
expect(appTree.read('my-app/index.html', 'utf-8')).toContain('main.jsx');
|
||||
expect(appTree.exists('my-app/src/main.jsx')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should setup the nx vite dev server builder if bundler is vite', async () => {
|
||||
|
||||
@ -11,6 +11,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script type="module" src="/src/<%= js ? 'main.jsx' : 'main.tsx' %>"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -42,6 +42,7 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
const templateVariables = {
|
||||
...names(options.name),
|
||||
...options,
|
||||
js: !!options.js, // Ensure this is defined in template
|
||||
tmpl: '',
|
||||
offsetFromRoot: offsetFromRoot(options.appProjectRoot),
|
||||
appTests,
|
||||
@ -155,7 +156,9 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
|
||||
);
|
||||
|
||||
if (options.js) {
|
||||
toJS(host);
|
||||
toJS(host, {
|
||||
useJsx: options.bundler === 'vite',
|
||||
});
|
||||
}
|
||||
|
||||
createTsConfig(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user