diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..a4e7cd5 Binary files /dev/null and b/.DS_Store differ diff --git a/examples/.DS_Store b/examples/.DS_Store new file mode 100644 index 0000000..4a39421 Binary files /dev/null and b/examples/.DS_Store differ diff --git a/examples/rollup/rollup.config.js b/examples/rollup/rollup.config.js index 7ba7ef4..f1f85ee 100644 --- a/examples/rollup/rollup.config.js +++ b/examples/rollup/rollup.config.js @@ -26,6 +26,7 @@ export default { format: "esm", }, plugins: [ + VueSource({}), vue({ exposeFilename: true, }), @@ -46,7 +47,6 @@ export default { svg({ base64: true, }), - VueSource({}), liveServer({ port: 3000, wait: 1000, diff --git a/examples/vite/src/App.vue b/examples/vite/src/App.vue index dc5a801..6f2ebb1 100644 --- a/examples/vite/src/App.vue +++ b/examples/vite/src/App.vue @@ -1,4 +1,4 @@ - diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..db74382 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/core/constants.ts b/src/core/constants.ts index 7445e99..db59882 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -8,3 +8,5 @@ export const ElementTypes = { ELEMENT: 0, COMPONENT: 1, }; + +export const TagTypes = [ElementTypes.ELEMENT, ElementTypes.COMPONENT]; diff --git a/src/core/index.ts b/src/core/index.ts index 23bf330..c33917c 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -1,51 +1,32 @@ -import { relative } from "path"; import type { UnpluginFactory } from "unplugin"; import { createUnplugin } from "unplugin"; -import { parse, transform } from "@vue/compiler-dom"; -import MagicString from "magic-string"; import type { Options } from "../types"; -import { ElementTypes, NodeTypes, TRACE_ID } from "./constants"; +import { parse_ID } from "./parse_ID"; +import { transform_SFC } from "./transform_SFC"; +// import { transform_JSX } from "./transform_JSX"; -const filterRE = /.(vue|jsx|tsx)$/; -const TagTypes = [ElementTypes.ELEMENT, ElementTypes.COMPONENT]; +const includeRE = /.((vue\?vue)|(vue|jsx|tsx)$)/; export const unpluginFactory: UnpluginFactory = (options = {}) => { - const { rootDir = process.cwd() } = options; - if (process.env.NODE_ENV !== "development") { return { name: "unplugin-vue-source", }; } + const { rootDir = process.cwd() } = options; + return { name: "unplugin-vue-source", enforce: "pre", transformInclude(id) { - return filterRE.test(id); + return includeRE.test(id); }, - transform(raw, id) { - const relativePath = `/${relative(rootDir, id)}`; - - const s = new MagicString(raw); - transform(parse(raw), { - nodeTransforms: [ - (node) => { - if ( - node.type === NodeTypes.ELEMENT && - TagTypes.includes(node.tagType as any) - ) { - const { line, column, offset } = node.loc.start; - const startIndex = offset + node.tag.length + 1; - s.prependLeft( - startIndex, - ` ${TRACE_ID}="${relativePath}:${line}:${column}"` - ); - } - }, - ], - }); - return s.toString(); + transform(code, id) { + const { filename, query } = parse_ID(id, rootDir); + if (!query.type || query.type === "template") { + return transform_SFC(filename, code); + } }, }; }; diff --git a/src/core/parse_ID.ts b/src/core/parse_ID.ts new file mode 100644 index 0000000..9cf71ef --- /dev/null +++ b/src/core/parse_ID.ts @@ -0,0 +1,29 @@ +import { extname } from "path"; + +export interface VueQuery { + vue?: boolean; + src?: string; + type?: "script" | "template" | "style" | "custom"; + lang?: string; +} + +export function parse_ID( + id: string, + rootDir: string +): { + filename: string; + ext: string; + query: VueQuery; +} { + const [filename, rawQuery] = id.split(`?`, 2); + const query = Object.fromEntries(new URLSearchParams(rawQuery)) as VueQuery; + if (query.vue != null) { + query.vue = true; + } + + return { + filename: filename.replace(rootDir, ""), + ext: extname(filename).slice(1), + query, + }; +} diff --git a/src/core/transform_JSX.ts b/src/core/transform_JSX.ts new file mode 100644 index 0000000..353a6aa --- /dev/null +++ b/src/core/transform_JSX.ts @@ -0,0 +1,3 @@ +export function transform_JSX(filename: string, code: string, tsx: boolean) { + return undefined; +} diff --git a/src/core/transform_SFC.ts b/src/core/transform_SFC.ts new file mode 100644 index 0000000..deba233 --- /dev/null +++ b/src/core/transform_SFC.ts @@ -0,0 +1,28 @@ +import { parse, transform } from "@vue/compiler-dom"; +import MagicString from "magic-string"; +import { NodeTypes, TRACE_ID, TagTypes } from "./constants"; + +export function transform_SFC(filename: string, code: string) { + const s = new MagicString(code); + + const ast = parse(code); + transform(ast, { + nodeTransforms: [ + (node) => { + if ( + node.type === NodeTypes.ELEMENT && + TagTypes.includes(node.tagType as any) + ) { + const { line, column, offset } = node.loc.start; + const startIndex = offset + node.tag.length + 1; + s.prependLeft( + startIndex, + ` ${TRACE_ID}="${filename}:${line}:${column}"` + ); + } + }, + ], + }); + + return s.toString(); +}