diff --git a/README.md b/README.md
index 4bbefd4..6fe6fc9 100644
--- a/README.md
+++ b/README.md
@@ -212,7 +212,12 @@ build({
The following show the default values of the configuration
```ts
-interface Options {
+export interface Options {
+ /** @default '**\/*.{vue,jsx,tsx}' */
+ include?: string | RegExp | (string | RegExp)[];
+ /** @default 'node_modules/**' */
+ exclude?: string | RegExp | (string | RegExp)[];
+
/**
* source root path
*
@@ -226,10 +231,12 @@ interface Options {
*/
sourceMap?: boolean;
- /** @default '**\/*.{vue,jsx,tsx}' */
- include?: string | RegExp | (string | RegExp)[];
- /** @default 'node_modules/**' */
- exclude?: string | RegExp | (string | RegExp)[];
+ /**
+ * Array containing the plugins that you want to enable.
+ *
+ * @default ['jsx', 'typescript']
+ */
+ babelParserPlugins?: ParserPlugin[];
}
```
diff --git a/examples/rollup/src/components/Github.vue b/examples/rollup/src/components/Github.vue
new file mode 100644
index 0000000..b7787c9
--- /dev/null
+++ b/examples/rollup/src/components/Github.vue
@@ -0,0 +1,16 @@
+
diff --git a/examples/rollup/src/components/HelloWorld.tsx b/examples/rollup/src/components/HelloWorld.tsx
index 9902618..2ee292d 100644
--- a/examples/rollup/src/components/HelloWorld.tsx
+++ b/examples/rollup/src/components/HelloWorld.tsx
@@ -1,4 +1,5 @@
import { defineComponent } from 'vue';
+import Github from './Github.vue';
export default defineComponent({
props: { msg: String },
@@ -10,12 +11,7 @@ export default defineComponent({
Inspect the element to see the __source
-
- Github
-
+
);
diff --git a/examples/vite/src/components/Github.vue b/examples/vite/src/components/Github.vue
new file mode 100644
index 0000000..b7787c9
--- /dev/null
+++ b/examples/vite/src/components/Github.vue
@@ -0,0 +1,16 @@
+
diff --git a/examples/vite/src/components/HelloWorld.tsx b/examples/vite/src/components/HelloWorld.tsx
index 5f6c5e6..b09dbcc 100644
--- a/examples/vite/src/components/HelloWorld.tsx
+++ b/examples/vite/src/components/HelloWorld.tsx
@@ -1,3 +1,5 @@
+import Github from './Github.vue';
+
export default function HelloWorld({ msg }: { msg: string }) {
return (
<>
@@ -6,12 +8,7 @@ export default function HelloWorld({ msg }: { msg: string }) {
Inspect the element to see the __source
-
- Github
-
+
>
);
diff --git a/examples/vite/vite.config.ts b/examples/vite/vite.config.ts
index 106ea9f..79778ce 100644
--- a/examples/vite/vite.config.ts
+++ b/examples/vite/vite.config.ts
@@ -11,4 +11,7 @@ export default defineConfig({
jsxFragment: 'Fragment',
jsxInject: "import { h, Fragment } from 'vue';",
},
+ server: {
+ port: 3000,
+ },
});
diff --git a/examples/webpack/src/components/Github.vue b/examples/webpack/src/components/Github.vue
new file mode 100644
index 0000000..b7787c9
--- /dev/null
+++ b/examples/webpack/src/components/Github.vue
@@ -0,0 +1,16 @@
+
diff --git a/examples/webpack/src/components/HelloWorld.tsx b/examples/webpack/src/components/HelloWorld.tsx
index 5f6c5e6..b09dbcc 100644
--- a/examples/webpack/src/components/HelloWorld.tsx
+++ b/examples/webpack/src/components/HelloWorld.tsx
@@ -1,3 +1,5 @@
+import Github from './Github.vue';
+
export default function HelloWorld({ msg }: { msg: string }) {
return (
<>
@@ -6,12 +8,7 @@ export default function HelloWorld({ msg }: { msg: string }) {
Inspect the element to see the __source
-
- Github
-
+
>
);
diff --git a/examples/webpack/vue.config.js b/examples/webpack/vue.config.js
index 108b8ab..3d2c4a3 100644
--- a/examples/webpack/vue.config.js
+++ b/examples/webpack/vue.config.js
@@ -1,9 +1,12 @@
-const { defineConfig } = require("@vue/cli-service");
+const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
configureWebpack: {
plugins: [
- require("unplugin-vue-source/webpack")(),
- require("unplugin-vue-jsx/webpack")(),
+ require('unplugin-vue-source/webpack')(),
+ require('unplugin-vue-jsx/webpack')(),
],
},
+ devServer: {
+ port: 3000,
+ },
});
diff --git a/src/core/index.ts b/src/core/index.ts
index 379fecb..648a0fc 100644
--- a/src/core/index.ts
+++ b/src/core/index.ts
@@ -1,7 +1,6 @@
import { type UnpluginFactory, createUnplugin } from 'unplugin';
import { createFilter } from '@rollup/pluginutils';
import { type ResolvedOptions, type Options } from '../types';
-import { TRACE_ID } from './constants';
import { isDev } from './isDev';
import { parse_ID } from './parse_ID';
import { transform } from './transform';
@@ -21,21 +20,8 @@ export const unpluginFactory: UnpluginFactory = (options = {}) => {
enforce: 'pre',
transformInclude(id) {
- const { file, isSfc, query } = parse_ID(id);
-
- if (query.raw == null && filter(file)) {
- if (isSfc && query.type !== 'template') {
- return (
- // vite-plugin-vue
- !query[TRACE_ID] &&
- // rollup-plugin-vue
- !query['rollup-plugin-vue']
- );
- }
-
- // vue cli | vue-loader | tsx | jsx
- return true;
- }
+ const { file, query } = parse_ID(id);
+ return query.raw == null && filter(file);
},
transform(code, id) {
return transform(code, id, opts);
@@ -45,10 +31,11 @@ export const unpluginFactory: UnpluginFactory = (options = {}) => {
function resolveOptions(opts: Options): ResolvedOptions {
return {
- root: opts.root ?? process.cwd(),
- sourceMap: opts.sourceMap ?? false,
include: opts.include ?? '**/*.{vue,jsx,tsx}',
exclude: opts.exclude ?? 'node_modules/**',
+ root: opts.root ?? process.cwd(),
+ sourceMap: opts.sourceMap ?? false,
+ babelParserPlugins: opts.babelParserPlugins ?? [],
};
}
diff --git a/src/core/parse_ID.ts b/src/core/parse_ID.ts
index fc5039c..befb97c 100644
--- a/src/core/parse_ID.ts
+++ b/src/core/parse_ID.ts
@@ -12,18 +12,10 @@ export function parse_ID(id: string, root = '') {
const ext = extname(file).slice(1);
const query = Object.fromEntries(new URLSearchParams(rawQuery)) as VueQuery;
- if (ext === 'vue') {
- return {
- file: file.replace(root, ''),
- isSfc: true,
- query,
- };
- }
-
return {
file: file.replace(root, ''),
- isJsx: true,
- isTsx: ext.includes('ts'),
+ isSfc: ext === 'vue',
+ isTsx: ext.startsWith('ts'),
query,
};
}
diff --git a/src/core/transform.ts b/src/core/transform.ts
index f1cc962..1142272 100644
--- a/src/core/transform.ts
+++ b/src/core/transform.ts
@@ -6,16 +6,20 @@ import { parse_ID } from './parse_ID';
import { transform_SFC } from './transform_SFC';
import { transform_JSX } from './transform_JSX';
-export function transform(code: string, id: string, options: ResolvedOptions) {
- const { root, sourceMap } = options;
+const skipRE = new RegExp(` ${TRACE_ID}=['"].+:[0-9]+:[0-9]+['"]`);
+
+export function transform(code: string, id: string, opts: ResolvedOptions) {
+ if (skipRE.test(code)) return;
+
+ const { root, sourceMap } = opts;
const s = new MagicString(code);
const parsed = parse_ID(id, root);
if (parsed.isSfc) {
- transform_SFC(code, replace);
+ transform_SFC(code, replace, opts);
} else {
- transform_JSX(code, replace, parsed);
+ transform_JSX(code, replace, parsed, opts);
}
function replace(pos: Position) {
diff --git a/src/core/transform_JSX.ts b/src/core/transform_JSX.ts
index bbbba1e..0c66c47 100644
--- a/src/core/transform_JSX.ts
+++ b/src/core/transform_JSX.ts
@@ -1,6 +1,7 @@
-import type { Position } from '@vue/compiler-dom';
+import { type Position } from '@vue/compiler-dom';
import { traverse, types as t } from '@babel/core';
import { parse, ParserPlugin } from '@babel/parser';
+import { type ResolvedOptions } from '../types';
export function transform_JSX(
code: string,
@@ -11,17 +12,19 @@ export function transform_JSX(
startLine?: number;
startColumn?: number;
},
+ opts: ResolvedOptions,
) {
const { isTsx, startIndex = 0, startLine = 1, startColumn = 1 } = options;
- const plugins: ParserPlugin[] = ['jsx'];
+ const pluginSet = new Set(opts.babelParserPlugins);
+ pluginSet.add('jsx');
if (isTsx) {
- plugins.push('typescript');
+ pluginSet.add('typescript');
}
const ast = parse(code, {
sourceType: 'unambiguous',
- plugins,
+ plugins: [...pluginSet] as ParserPlugin[],
startLine,
// babel start at 0
startColumn: startColumn - 1,
diff --git a/src/core/transform_SFC.ts b/src/core/transform_SFC.ts
index 4518657..5e2b6ae 100644
--- a/src/core/transform_SFC.ts
+++ b/src/core/transform_SFC.ts
@@ -1,15 +1,21 @@
-import type {
- ElementNode,
- AttributeNode,
- Position,
- RootNode,
- TextNode,
+import {
+ type ElementNode,
+ type AttributeNode,
+ type Position,
+ type RootNode,
+ type TextNode,
+ parse,
+ transform,
} from '@vue/compiler-dom';
-import { parse, transform } from '@vue/compiler-dom';
+import { type ResolvedOptions } from '../types';
import { NodeTypes, TagTypes } from './constants';
import { transform_JSX } from './transform_JSX';
-export function transform_SFC(code: string, cb: (pos: Position) => void) {
+export function transform_SFC(
+ code: string,
+ cb: (pos: Position) => void,
+ opts: ResolvedOptions,
+) {
const ast = parse(code);
transform(ast, {
nodeTransforms: [
@@ -27,13 +33,13 @@ export function transform_SFC(code: string, cb: (pos: Position) => void) {
],
});
- const jsxOpts = resolveJsxOptions(ast);
+ const jsxOpts = resolveJsxOptsByScript(ast);
if (jsxOpts) {
- transform_JSX(jsxOpts.code, cb, jsxOpts);
+ transform_JSX(jsxOpts.code, cb, jsxOpts, opts);
}
}
-function resolveJsxOptions(ast: RootNode) {
+function resolveJsxOptsByScript(ast: RootNode) {
const scriptNode = (ast.children as ElementNode[]).find(
(node) => node.tag === 'script',
);
diff --git a/src/types.ts b/src/types.ts
index 5371bc9..9bc3dda 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,4 +1,11 @@
+import { ParserPlugin } from '@babel/parser';
+
export interface Options {
+ /** @default '**\/*.{vue,jsx,tsx}' */
+ include?: string | RegExp | (string | RegExp)[];
+ /** @default 'node_modules/**' */
+ exclude?: string | RegExp | (string | RegExp)[];
+
/**
* source root path
*
@@ -12,10 +19,12 @@ export interface Options {
*/
sourceMap?: boolean;
- /** @default '**\/*.{vue,jsx,tsx}' */
- include?: string | RegExp | (string | RegExp)[];
- /** @default 'node_modules/**' */
- exclude?: string | RegExp | (string | RegExp)[];
+ /**
+ * Array containing the plugins that you want to enable.
+ *
+ * @default ['jsx', 'typescript']
+ */
+ babelParserPlugins?: ParserPlugin[];
}
export type ResolvedOptions = Required;
diff --git a/test/fixtures.test.ts b/test/fixtures.test.ts
index e02b09d..07274c8 100644
--- a/test/fixtures.test.ts
+++ b/test/fixtures.test.ts
@@ -1,5 +1,5 @@
import { readFileSync } from 'node:fs';
-import { extname, join, resolve } from 'node:path';
+import { basename, dirname, extname, join, resolve } from 'node:path';
import { expect, test } from 'vitest';
import { format, Options } from 'prettier';
import fg from 'fast-glob';
@@ -19,7 +19,11 @@ test.each(fixtures)('transform %s', async (name) => {
const input = readCodeString(filename);
const output = readCodeString(filename, `output${extname(filename)}`);
- const result = transform(input, filename, options);
+ const result = transform(input, filename, options)!;
+
+ if (basename(dirname(name)) === 'vue-skip') {
+ return expect(result).toBeUndefined();
+ }
expect(
await formatCode(result.code, {
@@ -35,7 +39,7 @@ test.each(fixtures)('transform %s', async (name) => {
}),
).toEqual(sourceMap);
} else {
- expect(result.map).toBe(null);
+ expect(result.map).toBeNull();
}
});
diff --git a/test/fixtures/vue-skip/input.vue b/test/fixtures/vue-skip/input.vue
new file mode 100644
index 0000000..a1364ce
--- /dev/null
+++ b/test/fixtures/vue-skip/input.vue
@@ -0,0 +1,3 @@
+
+ test
+
diff --git a/test/fixtures/vue-skip/options.ts b/test/fixtures/vue-skip/options.ts
new file mode 100644
index 0000000..19d8e2b
--- /dev/null
+++ b/test/fixtures/vue-skip/options.ts
@@ -0,0 +1,4 @@
+export default {
+ root: process.cwd(),
+ sourceMap: false,
+};
diff --git a/test/fixtures/vue-skip/output.vue b/test/fixtures/vue-skip/output.vue
new file mode 100644
index 0000000..a1364ce
--- /dev/null
+++ b/test/fixtures/vue-skip/output.vue
@@ -0,0 +1,3 @@
+
+ test
+