Skip to content

Commit

Permalink
feat: Add option babelParserPlugins
Browse files Browse the repository at this point in the history
  • Loading branch information
zjxxxxxxxxx committed Dec 11, 2023
1 parent 13d1ee0 commit 7d08f70
Show file tree
Hide file tree
Showing 19 changed files with 146 additions and 80 deletions.
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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[];
}
```

Expand Down
16 changes: 16 additions & 0 deletions examples/rollup/src/components/Github.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="tsx">
import { defineComponent } from 'vue';
export default defineComponent({
render() {
return (
<a
target="_black"
href="https://github.com/zjxxxxxxxxx/unplugin-vue-source"
>
Github
</a>
);
},
});
</script>
8 changes: 2 additions & 6 deletions examples/rollup/src/components/HelloWorld.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineComponent } from 'vue';
import Github from './Github.vue';

export default defineComponent({
props: { msg: String },
Expand All @@ -10,12 +11,7 @@ export default defineComponent({
Inspect the element to see the <code>__source</code>
</p>
<p>
<a
target="_black"
href="https://github.com/zjxxxxxxxxx/unplugin-vue-source"
>
Github
</a>
<Github />
</p>
</div>
);
Expand Down
16 changes: 16 additions & 0 deletions examples/vite/src/components/Github.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="tsx">
import { defineComponent } from 'vue';
export default defineComponent({
render() {
return (
<a
target="_black"
href="https://github.com/zjxxxxxxxxx/unplugin-vue-source"
>
Github
</a>
);
},
});
</script>
9 changes: 3 additions & 6 deletions examples/vite/src/components/HelloWorld.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Github from './Github.vue';

export default function HelloWorld({ msg }: { msg: string }) {
return (
<>
Expand All @@ -6,12 +8,7 @@ export default function HelloWorld({ msg }: { msg: string }) {
Inspect the element to see the <code>__source</code>
</p>
<p>
<a
target="_black"
href="https://github.com/zjxxxxxxxxx/unplugin-vue-source"
>
Github
</a>
<Github />
</p>
</>
);
Expand Down
3 changes: 3 additions & 0 deletions examples/vite/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ export default defineConfig({
jsxFragment: 'Fragment',
jsxInject: "import { h, Fragment } from 'vue';",
},
server: {
port: 3000,
},
});
16 changes: 16 additions & 0 deletions examples/webpack/src/components/Github.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="tsx">
import { defineComponent } from 'vue';
export default defineComponent({
render() {
return (
<a
target="_black"
href="https://github.com/zjxxxxxxxxx/unplugin-vue-source"
>
Github
</a>
);
},
});
</script>
9 changes: 3 additions & 6 deletions examples/webpack/src/components/HelloWorld.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Github from './Github.vue';

export default function HelloWorld({ msg }: { msg: string }) {
return (
<>
Expand All @@ -6,12 +8,7 @@ export default function HelloWorld({ msg }: { msg: string }) {
Inspect the element to see the <code>__source</code>
</p>
<p>
<a
target="_black"
href="https://github.com/zjxxxxxxxxx/unplugin-vue-source"
>
Github
</a>
<Github />
</p>
</>
);
Expand Down
9 changes: 6 additions & 3 deletions examples/webpack/vue.config.js
Original file line number Diff line number Diff line change
@@ -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,
},
});
23 changes: 5 additions & 18 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -21,21 +20,8 @@ export const unpluginFactory: UnpluginFactory<Options> = (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);
Expand All @@ -45,10 +31,11 @@ export const unpluginFactory: UnpluginFactory<Options> = (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 ?? [],
};
}

Expand Down
12 changes: 2 additions & 10 deletions src/core/parse_ID.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
}
12 changes: 8 additions & 4 deletions src/core/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
11 changes: 7 additions & 4 deletions src/core/transform_JSX.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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,
Expand Down
28 changes: 17 additions & 11 deletions src/core/transform_SFC.ts
Original file line number Diff line number Diff line change
@@ -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: [
Expand All @@ -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',
);
Expand Down
17 changes: 13 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -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
*
Expand All @@ -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<Options>;
10 changes: 7 additions & 3 deletions test/fixtures.test.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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, {
Expand All @@ -35,7 +39,7 @@ test.each(fixtures)('transform %s', async (name) => {
}),
).toEqual(sourceMap);
} else {
expect(result.map).toBe(null);
expect(result.map).toBeNull();
}
});

Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/vue-skip/input.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template __source="/test/fixtures/vue/input.vue:1:1">
<div __source="/test/fixtures/vue/input.vue:2:3">test</div>
</template>
Loading

0 comments on commit 7d08f70

Please sign in to comment.