From 595a35df88ed2c2b43decf78a0259398eac07a33 Mon Sep 17 00:00:00 2001 From: Kai Vandivier <49666798+KaiVandivier@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:01:58 +0200 Subject: [PATCH] fix: handle jsx in js support [LIBS-633] (#871) * fix: jsx-in-js handling * docs: allowJsxInJs option * chore: typo * feat: add warning logs --- cli/config/makeViteConfig.mjs | 67 ++++++++++++++++++----------------- cli/src/commands/build.js | 21 ++++++++++- cli/src/commands/start.js | 25 +++++++++++-- docs/scripts/build.md | 4 +++ docs/scripts/start.md | 22 +++++++----- 5 files changed, 96 insertions(+), 43 deletions(-) diff --git a/cli/config/makeViteConfig.mjs b/cli/config/makeViteConfig.mjs index fa05e3992..3346b0afd 100644 --- a/cli/config/makeViteConfig.mjs +++ b/cli/config/makeViteConfig.mjs @@ -1,6 +1,7 @@ import react from '@vitejs/plugin-react' import { defineConfig, + mergeConfig, searchForWorkspaceRoot, transformWithEsbuild, } from 'vite' @@ -17,28 +18,33 @@ import dynamicImport from 'vite-plugin-dynamic-import' * Vite normally throws an error when JSX syntax is used in a file without a * .jsx or .tsx extension. This is by design, in order to improve transform * performance by not parsing JS files for JSX. - * This plugin is 1 of 2 config options that allow JSX to be used in - * .js or .ts files -- the options in `optimizeDeps` below are part 2. + * + * This plugin and the `optimizeDeps` options in this config object, + * along with the `jsxRuntime: 'classic'` option in the React plugin of the main + * config, can enable support for JSX in .js files. This config object is + * merged with the main config if the `--allowJsxInJs` flag is passed + * to the CLI * - * NB: State-preserving HMR will not work on React components unless they have - * a .jsx or .tsx extension though, unfortunately - * - * todo: deprecate -- this and optimize deps below have a performance cost - * on startup + * todo: deprecate -- this config has a performance cost, especially on startup */ -const jsxInJSPlugin = { - name: 'treat-js-files-as-jsx', - async transform(code, id) { - if (!id.match(/src\/.*\.js$/)) { - return null - } - // todo: consider JSX warning if - // Use the exposed transform from vite, instead of directly - // transforming with esbuild - return transformWithEsbuild(code, id, { - loader: 'jsx', - jsx: 'automatic', - }) +const jsxInJsConfig = { + plugins: [{ + name: 'treat-js-files-as-jsx', + async transform(code, id) { + if (!id.match(/src\/.*\.js$/)) { + return null + } + // Use the exposed transform from vite, instead of directly + // transforming with esbuild + return transformWithEsbuild(code, id, { + loader: 'jsx', + jsx: 'automatic', + }) + }, + }], + optimizeDeps: { + force: true, + esbuildOptions: { loader: { '.js': 'jsx' } }, }, } @@ -107,8 +113,8 @@ const getBuildInputs = (config, paths) => { } // https://vitejs.dev/config/ -export default ({ paths, config, env, host }) => { - return defineConfig({ +export default ({ paths, config, env, host, force, allowJsxInJs }) => { + const baseConfig = defineConfig({ // Need to specify the location of the app root, since this CLI command // gets run in a different directory than the bootstrapped app root: paths.shell, @@ -153,8 +159,6 @@ export default ({ paths, config, env, host }) => { }, plugins: [ - // Allow JSX in .js files pt. 1 - jsxInJSPlugin, /** * Allows the dynamic import of `moment/dist/locale/${locale}` * in /adapter/src/utils/localeUtils.js. @@ -164,16 +168,15 @@ export default ({ paths, config, env, host }) => { dynamicImport(), react({ babel: { plugins: ['styled-jsx/babel'] }, - // Enables HMR for .js files: - jsxRuntime: 'classic', + // todo: deprecate with other jsx-in-js config + // This option allows HMR of JSX-in-JS files, + // but it isn't possible to add with merge config: + jsxRuntime: allowJsxInJs ? 'classic' : 'automatic', }), ], - // Allow JSX in .js pt. 2 - // todo: deprecate - has a performance cost on startup - optimizeDeps: { - force: true, - esbuildOptions: { loader: { '.js': 'jsx' } }, - }, + optimizeDeps: { force }, }) + + return allowJsxInJs ? mergeConfig(baseConfig, jsxInJsConfig) : baseConfig } diff --git a/cli/src/commands/build.js b/cli/src/commands/build.js index 820439619..1acc73a40 100644 --- a/cli/src/commands/build.js +++ b/cli/src/commands/build.js @@ -59,6 +59,7 @@ const handler = async ({ verify, force, pack: packAppOutput, + allowJsxInJs, }) => { const paths = makePaths(cwd) @@ -136,7 +137,20 @@ const handler = async ({ '../../config/makeViteConfig.mjs' ) const env = getEnv({ config, ...appParameters }) - const viteConfig = createConfig({ paths, config, env }) + if (allowJsxInJs) { + reporter.warn( + 'Adding Vite config to allow JSX syntax in .js files. This is deprecated and will be removed in future versions.' + ) + reporter.warn( + 'Consider using the migration script `yarn d2-app-scripts migrate js-to-jsx` to rename your files to use .jsx extensions.' + ) + } + const viteConfig = createConfig({ + paths, + config, + env, + allowJsxInJs, + }) await build(viteConfig) if (config.pwa.enabled) { @@ -235,6 +249,11 @@ const command = { 'Build in standalone mode (overrides the d2.config.js setting)', default: undefined, }, + allowJsxInJs: { + type: 'boolean', + description: + 'Add Vite config to handle JSX in .js files. DEPRECATED: Will be removed in @dhis2/cli-app-scripts v13. Consider using the migration script `d2-app-scripts migrate js-to-jsx` to avoid needing this option', + }, }, handler, } diff --git a/cli/src/commands/start.js b/cli/src/commands/start.js index 8853489f5..b1844675e 100644 --- a/cli/src/commands/start.js +++ b/cli/src/commands/start.js @@ -23,6 +23,7 @@ const handler = async ({ proxy, proxyPort, host, + allowJsxInJs, }) => { const paths = makePaths(cwd) @@ -131,7 +132,22 @@ const handler = async ({ const { default: createConfig } = await import( '../../config/makeViteConfig.mjs' ) - const viteConfig = createConfig({ config, paths, env, host }) + if (allowJsxInJs) { + reporter.warn( + 'Adding Vite config to allow JSX syntax in .js files. This is deprecated and will be removed in future versions.' + ) + reporter.warn( + 'Consider using the migration script `yarn d2-app-scripts migrate js-to-jsx` to rename your files to use .jsx extensions.' + ) + } + const viteConfig = createConfig({ + config, + paths, + env, + host, + force, + allowJsxInJs, + }) const server = await createServer(viteConfig) const location = config.entryPoints.plugin @@ -176,7 +192,7 @@ const command = { force: { type: 'boolean', description: - 'Force updating the app shell. Normally, this is only done when a new version of @dhis2/cli-app-scripts is detected', + 'Force updating the app shell; normally, this is only done when a new version of @dhis2/cli-app-scripts is detected. Also passes the --force option to the Vite server to reoptimize dependencies', }, port: { alias: 'p', @@ -199,6 +215,11 @@ const command = { description: 'Exposes the server on the local network. Can optionally provide an address to use. [boolean or string]', }, + allowJsxInJs: { + type: 'boolean', + description: + 'Add Vite config to handle JSX in .js files. DEPRECATED: Will be removed in @dhis2/cli-app-scripts v13. Consider using the migration script `d2-app-scripts migrate js-to-jsx` to avoid needing this option', + }, }, handler, } diff --git a/docs/scripts/build.md b/docs/scripts/build.md index 7e820b0b7..ac98e5f75 100644 --- a/docs/scripts/build.md +++ b/docs/scripts/build.md @@ -25,4 +25,8 @@ Options: --watch Watch source files for changes [boolean] [default: false] --standalone Build in standalone mode (overrides the d2.config.js setting) [boolean] + --allowJsxInJs Add Vite config to handle JSX in .js files. DEPRECATED: Will + be removed in @dhis2/cli-app-scripts v13. Consider using the + migration script `d2-app-scripts migrate js-to-jsx` to avoid + needing this option [boolean] ``` diff --git a/docs/scripts/start.md b/docs/scripts/start.md index 0095975f0..697f6337c 100644 --- a/docs/scripts/start.md +++ b/docs/scripts/start.md @@ -19,13 +19,19 @@ Global Options: --config Path to JSON config file Options: - --cwd working directory to use (defaults to cwd) - --force Force updating the app shell. Normally, this is only done when a - new version of @dhis2/cli-app-scripts is detected [boolean] - --port, -p The port to use when running the development server + --cwd working directory to use (defaults to cwd) + --force Force updating the app shell; normally, this is only done when + a new version of @dhis2/cli-app-scripts is detected. Also + passes the --force option to the Vite server to re-optimize + dependencies [boolean] + --port, -p The port to use when running the development server [number] [default: 3000] - --proxy, -P The remote DHIS2 instance the proxy should point to [string] - --proxyPort The port to use when running the proxy [number] [default: 8080] - --host Exposes the server on the local network. Can optionally provide - an address to use. [boolean or string] + --proxy, -P The remote DHIS2 instance the proxy should point to [string] + --proxyPort The port to use when running the proxy[number] [default: 8080] + --host Exposes the server on the local network. Can optionally + provide an address to use. [boolean or string] + --allowJsxInJs Add Vite config to handle JSX in .js files. DEPRECATED: Will + be removed in @dhis2/cli-app-scripts v13. Consider using the + migration script `d2-app-scripts migrate js-to-jsx` to avoid + needing this option [boolean] ```