From 9dc5413cbd5a96aa80662db8db56f27d2c4647e6 Mon Sep 17 00:00:00 2001 From: Nick Williams Date: Thu, 16 Feb 2023 12:45:08 +0000 Subject: [PATCH] fix(vite): respect `isCustomElement` config for jsx transform (#19053) --- packages/schema/build.config.ts | 1 + packages/schema/package.json | 1 + packages/schema/src/config/vite.ts | 8 +++++++ packages/schema/src/types/config.ts | 9 +++++++- packages/vite/src/client.ts | 2 +- packages/vite/src/server.ts | 2 +- packages/vite/src/vite.ts | 6 +++-- pnpm-lock.yaml | 32 ++++++++++++++------------ test/basic.test.ts | 9 ++++++++ test/fixtures/basic/components/Tsx.tsx | 8 +++++++ test/fixtures/basic/nuxt.config.ts | 7 ++++++ test/fixtures/basic/pages/jsx.vue | 5 ++++ 12 files changed, 70 insertions(+), 20 deletions(-) create mode 100644 test/fixtures/basic/components/Tsx.tsx create mode 100644 test/fixtures/basic/pages/jsx.vue diff --git a/packages/schema/build.config.ts b/packages/schema/build.config.ts index 6016baba15..beb7e14bf3 100644 --- a/packages/schema/build.config.ts +++ b/packages/schema/build.config.ts @@ -30,6 +30,7 @@ export default defineBuildConfig({ 'rollup-plugin-visualizer', 'vite', '@vitejs/plugin-vue', + '@vitejs/plugin-vue-jsx', 'mini-css-extract-plugin', 'terser-webpack-plugin', 'css-minimizer-webpack-plugin', diff --git a/packages/schema/package.json b/packages/schema/package.json index dee997ed44..945725450f 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -18,6 +18,7 @@ "@types/semver": "^7.3.13", "@unhead/schema": "^1.0.22", "@vitejs/plugin-vue": "^4.0.0", + "@vitejs/plugin-vue-jsx": "^3.0.0", "nitropack": "^2.2.1", "unbuild": "latest", "vite": "~4.1.1" diff --git a/packages/schema/src/config/vite.ts b/packages/schema/src/config/vite.ts index 2add95dc35..e048e86c83 100644 --- a/packages/schema/src/config/vite.ts +++ b/packages/schema/src/config/vite.ts @@ -43,6 +43,14 @@ export default defineUntypedSchema({ } } }, + vueJsx: { + $resolve: async (val, get) => { + return { + isCustomElement: (await get('vue')).compilerOptions?.isCustomElement, + ...(val || {}) + } + } + }, optimizeDeps: { exclude: { $resolve: async (val, get) => [ diff --git a/packages/schema/src/types/config.ts b/packages/schema/src/types/config.ts index 66b5b20fd3..ed9827f875 100644 --- a/packages/schema/src/types/config.ts +++ b/packages/schema/src/types/config.ts @@ -2,6 +2,7 @@ import type { KeepAliveProps, TransitionProps } from 'vue' import type { ConfigSchema } from '../../schema/config' import type { ServerOptions as ViteServerOptions, UserConfig as ViteUserConfig } from 'vite' import type { Options as VuePluginOptions } from '@vitejs/plugin-vue' +import type { Options as VueJsxPluginOptions } from '@vitejs/plugin-vue-jsx' import type { AppHeadMetaObject } from './meta' import type { Nuxt } from './nuxt' import type { SchemaDefinition } from 'untyped' @@ -95,10 +96,16 @@ export interface NuxtOptions extends Omit { export interface ViteConfig extends ViteUserConfig { /** * Options passed to @vitejs/plugin-vue - * @see https://github.com/vitejs/vite/tree/main/packages/plugin-vue + * @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue */ vue?: VuePluginOptions + /** + * Options passed to @vitejs/plugin-vue-jsx + * @see https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx + */ + vueJsx?: VueJsxPluginOptions + /** * Bundler for dev time server-side rendering. * @default 'vite-node' diff --git a/packages/vite/src/client.ts b/packages/vite/src/client.ts index 43d7a92f51..8955f1270c 100644 --- a/packages/vite/src/client.ts +++ b/packages/vite/src/client.ts @@ -61,7 +61,7 @@ export async function buildClient (ctx: ViteBuildContext) { plugins: [ cacheDirPlugin(ctx.nuxt.options.rootDir, 'client'), vuePlugin(ctx.config.vue), - viteJsxPlugin(), + viteJsxPlugin(ctx.config.vueJsx), devStyleSSRPlugin({ srcDir: ctx.nuxt.options.srcDir, buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir) diff --git a/packages/vite/src/server.ts b/packages/vite/src/server.ts index 13d27690bc..34cec5cdb9 100644 --- a/packages/vite/src/server.ts +++ b/packages/vite/src/server.ts @@ -110,7 +110,7 @@ export async function buildServer (ctx: ViteBuildContext) { plugins: [ cacheDirPlugin(ctx.nuxt.options.rootDir, 'server'), vuePlugin(ctx.config.vue), - viteJsxPlugin() + viteJsxPlugin(ctx.config.vueJsx) ] } as ViteOptions) diff --git a/packages/vite/src/vite.ts b/packages/vite/src/vite.ts index 9bc01523d7..07f7f4b68f 100644 --- a/packages/vite/src/vite.ts +++ b/packages/vite/src/vite.ts @@ -3,7 +3,8 @@ import { join, resolve } from 'pathe' import type { Nuxt } from '@nuxt/schema' import type { InlineConfig, SSROptions } from 'vite' import { logger, isIgnored, resolvePath, addVitePlugin } from '@nuxt/kit' -import type { Options } from '@vitejs/plugin-vue' +import type { Options as VueOptions } from '@vitejs/plugin-vue' +import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx' import replace from '@rollup/plugin-replace' import { sanitizeFilePath } from 'mlly' import { withoutLeadingSlash } from 'ufo' @@ -17,7 +18,8 @@ import { resolveCSSOptions } from './css' import { composableKeysPlugin } from './plugins/composable-keys' export interface ViteOptions extends InlineConfig { - vue?: Options + vue?: VueOptions + vueJsx?: VueJsxOptions ssr?: SSROptions devBundler?: 'vite-node' | 'legacy' } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0dc2a9f66a..a2bb6c7a72 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -513,6 +513,7 @@ importers: '@types/semver': ^7.3.13 '@unhead/schema': ^1.0.22 '@vitejs/plugin-vue': ^4.0.0 + '@vitejs/plugin-vue-jsx': ^3.0.0 c12: ^1.1.0 create-require: ^1.1.1 defu: ^6.1.2 @@ -548,6 +549,7 @@ importers: '@types/semver': 7.3.13 '@unhead/schema': 1.0.22 '@vitejs/plugin-vue': 4.0.0_vite@4.1.1 + '@vitejs/plugin-vue-jsx': 3.0.0_vite@4.1.1 nitropack: 2.2.1 unbuild: 1.1.1 vite: 4.1.1 @@ -849,7 +851,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.20.7 - dev: false /@babel/helper-compilation-targets/7.20.7_@babel+core@7.20.12: resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} @@ -881,7 +882,6 @@ packages: '@babel/helper-split-export-declaration': 7.18.6 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-environment-visitor/7.18.9: resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} @@ -905,7 +905,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.20.7 - dev: false /@babel/helper-module-imports/7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} @@ -933,12 +932,10 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.20.7 - dev: false /@babel/helper-plugin-utils/7.20.2: resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-replace-supers/7.20.7: resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==} @@ -952,7 +949,6 @@ packages: '@babel/types': 7.20.7 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-simple-access/7.20.2: resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} @@ -965,7 +961,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.20.7 - dev: false /@babel/helper-split-export-declaration/7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} @@ -1018,7 +1013,6 @@ packages: dependencies: '@babel/core': 7.20.12 '@babel/helper-plugin-utils': 7.20.2 - dev: false /@babel/plugin-syntax-typescript/7.20.0_@babel+core@7.20.12: resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} @@ -1028,7 +1022,6 @@ packages: dependencies: '@babel/core': 7.20.12 '@babel/helper-plugin-utils': 7.20.2 - dev: false /@babel/plugin-transform-typescript/7.20.13_@babel+core@7.20.12: resolution: {integrity: sha512-O7I/THxarGcDZxkgWKMUrk7NK1/WbHAg3Xx86gqS6x9MTrNL6AwIluuZ96ms4xeDe6AVx6rjHbWHP7x26EPQBA==} @@ -1042,7 +1035,6 @@ packages: '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.20.12 transitivePeerDependencies: - supports-color - dev: false /@babel/standalone/7.20.15: resolution: {integrity: sha512-B3LmZ1NHlTb2eFEaw8rftZc730Wh9MlmsH8ubb6IjsNoIk9+SQ2aAA0nrm/1806+PftPRAACPClmKTu8PG7Tew==} @@ -2764,6 +2756,21 @@ packages: - encoding - supports-color + /@vitejs/plugin-vue-jsx/3.0.0_vite@4.1.1: + resolution: {integrity: sha512-vurkuzgac5SYuxd2HUZqAFAWGTF10diKBwJNbCvnWijNZfXd+7jMtqjPFbGt7idOJUn584fP1Ar9j/GN2jQ3Ew==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 + vue: ^3.0.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/plugin-transform-typescript': 7.20.13_@babel+core@7.20.12 + '@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.20.12 + vite: 4.1.1 + transitivePeerDependencies: + - supports-color + dev: true + /@vitejs/plugin-vue-jsx/3.0.0_vite@4.1.1+vue@3.2.47: resolution: {integrity: sha512-vurkuzgac5SYuxd2HUZqAFAWGTF10diKBwJNbCvnWijNZfXd+7jMtqjPFbGt7idOJUn584fP1Ar9j/GN2jQ3Ew==} engines: {node: ^14.18.0 || >=16.0.0} @@ -2874,7 +2881,6 @@ packages: /@vue/babel-helper-vue-transform-on/1.0.2: resolution: {integrity: sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==} - dev: false /@vue/babel-plugin-jsx/1.1.1_@babel+core@7.20.12: resolution: {integrity: sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==} @@ -2891,7 +2897,6 @@ packages: transitivePeerDependencies: - '@babel/core' - supports-color - dev: false /@vue/compiler-core/3.2.47: resolution: {integrity: sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==} @@ -3573,7 +3578,6 @@ packages: /camelcase/6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - dev: false /caniuse-api/3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} @@ -5545,7 +5549,6 @@ packages: /html-tags/3.2.0: resolution: {integrity: sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==} engines: {node: '>=8'} - dev: false /htmlparser2/3.10.1: resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} @@ -8069,7 +8072,6 @@ packages: /svg-tags/1.0.0: resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} - dev: false /svgo/2.8.0: resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} diff --git a/test/basic.test.ts b/test/basic.test.ts index 1b0e5fc6f3..0c90ff43c3 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -76,6 +76,15 @@ describe('pages', () => { await expectNoClientErrors('/') }) + // TODO: support jsx with webpack + it.runIf(!isWebpack)('supports jsx', async () => { + const html = await $fetch('/jsx') + + // should import JSX/TSX components with custom elements + expect(html).toContain('TSX component') + expect(html).toContain('custom') + }) + it('respects aliases in page metadata', async () => { const html = await $fetch('/some-alias') expect(html).toContain('Hello Nuxt 3!') diff --git a/test/fixtures/basic/components/Tsx.tsx b/test/fixtures/basic/components/Tsx.tsx new file mode 100644 index 0000000000..160972e31c --- /dev/null +++ b/test/fixtures/basic/components/Tsx.tsx @@ -0,0 +1,8 @@ +export default defineComponent({ + render () { + return
+ TSX component + custom +
+ } +}) diff --git a/test/fixtures/basic/nuxt.config.ts b/test/fixtures/basic/nuxt.config.ts index e562b0151f..df9b888ac2 100644 --- a/test/fixtures/basic/nuxt.config.ts +++ b/test/fixtures/basic/nuxt.config.ts @@ -148,6 +148,13 @@ export default defineNuxtConfig({ }) } }, + vue: { + compilerOptions: { + isCustomElement: (tag) => { + return tag === 'custom-component' + } + } + }, experimental: { emitRouteChunkError: 'reload', inlineSSRStyles: id => !!id && !id.includes('assets.vue'), diff --git a/test/fixtures/basic/pages/jsx.vue b/test/fixtures/basic/pages/jsx.vue new file mode 100644 index 0000000000..8441c33671 --- /dev/null +++ b/test/fixtures/basic/pages/jsx.vue @@ -0,0 +1,5 @@ +