From a9da4618782677f1df7f51748f210035e6c16d72 Mon Sep 17 00:00:00 2001 From: Teages Date: Tue, 8 Apr 2025 23:39:41 +0800 Subject: [PATCH 1/2] fix(vue): force emit dts for build-in loader --- src/loaders/vue.ts | 12 +++- test/index.test.ts | 159 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 168 insertions(+), 3 deletions(-) diff --git a/src/loaders/vue.ts b/src/loaders/vue.ts index f382093..7dc4857 100644 --- a/src/loaders/vue.ts +++ b/src/loaders/vue.ts @@ -76,12 +76,13 @@ function defineVueLoader(options?: DefineVueLoaderOptions): Loader { ].filter((item) => !!item); // generate dts - await context.loadFile({ + const files = await context.loadFile({ path: `${input.path}.js`, srcPath: `${input.srcPath}.js`, extension: ".js", getContents: () => "export default {}", }); + addOutput(...(files?.filter((f) => f.declaration) || [])); const results = await Promise.all( blocks.map(async (data) => { @@ -99,7 +100,14 @@ function defineVueLoader(options?: DefineVueLoaderOptions): Loader { ); if (!modified) { - return; + addOutput({ + path: input.path, + srcPath: input.srcPath, + extension: ".vue", + contents: raw, + declaration: false, + }); + return output; } // skiped blocks diff --git a/test/index.test.ts b/test/index.test.ts index c7e3a59..da77087 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -638,8 +638,12 @@ describe("mkdist", () => { }); describe("mkdist with fallback vue loader", () => { + let mkdist: typeof import("../src/make").mkdist; + const consoleWarnSpy = vi.spyOn(console, "warn"); - beforeAll(() => { + beforeAll(async () => { + mkdist = (await import("../src/make")).mkdist; + vi.resetModules(); vi.doMock("vue-sfc-transformer/mkdist", async () => { throw new Error("vue-sfc-transformer is not installed"); @@ -718,6 +722,159 @@ describe("mkdist with fallback vue loader", () => { `); }); + it("emit types", async () => { + const rootDir = resolve(__dirname, "fixture"); + const { writtenFiles } = await mkdist({ + rootDir, + declaration: true, + addRelativeDeclarationExtensions: true, + }); + expect(writtenFiles.sort()).toEqual( + [ + "dist/README.md", + "dist/bar.d.ts", + "dist/bar.mjs", + "dist/demo.css", + "dist/dir-export.d.ts", + "dist/dir-export.mjs", + "dist/foo.mjs", + "dist/foo.d.ts", + "dist/index.mjs", + "dist/index.d.ts", + "dist/star/index.mjs", + "dist/star/index.d.ts", + "dist/star/other.mjs", + "dist/star/other.d.ts", + "dist/types.d.ts", + "dist/components/index.mjs", + "dist/components/index.d.ts", + "dist/components/blank.vue", + "dist/components/blank.vue.d.ts", + "dist/components/define-model.vue", + "dist/components/define-model.vue.d.ts", + "dist/components/emit-and-with-default.vue", + "dist/components/emit-and-with-default.vue.d.ts", + "dist/components/js.vue", + "dist/components/js.vue.d.ts", + "dist/components/script-multi-block.vue", + "dist/components/script-multi-block.vue.d.ts", + "dist/components/script-setup-ts.vue", + "dist/components/script-setup-ts.vue.d.ts", + "dist/components/ts.vue", + "dist/components/ts.vue.d.ts", + "dist/components/jsx.mjs", + "dist/components/tsx.mjs", + "dist/components/jsx.d.ts", + "dist/components/tsx.d.ts", + "dist/bar/index.mjs", + "dist/bar/index.d.ts", + "dist/bar/esm.mjs", + "dist/bar/esm.d.mts", + "dist/ts/test1.mjs", + "dist/ts/test2.mjs", + "dist/ts/test1.d.mts", + "dist/ts/test2.d.cts", + "dist/nested.css", + "dist/prop-types/index.mjs", + "dist/prop-types/index.d.ts", + ] + .map((f) => resolve(rootDir, f)) + .sort(), + ); + + expect(await readFile(resolve(rootDir, "dist/foo.d.ts"), "utf8")).toMatch( + "manual declaration", + ); + + expect(await readFile(resolve(rootDir, "dist/star/index.d.ts"), "utf8")) + .toMatchInlineSnapshot(` + "export * from "./other.js"; + export type { Other } from "./other.js"; + export declare function wonder(twinkle: import("./other.js").Other): string; + " + `); + + expect(await readFile(resolve(rootDir, "dist/dir-export.d.ts"), "utf8")) + .toMatchInlineSnapshot(` + "export { default as bar } from "./bar.js"; + export * from "./star/index.js"; + " + `); + + expect( + await readFile(resolve(rootDir, "dist/bar/esm.d.mts"), "utf8"), + ).toMatch("declare"); + + expect( + await readFile(resolve(rootDir, "dist/components/index.d.ts"), "utf8"), + ).toMatchInlineSnapshot(` + "export * as jsx from "./jsx.jsx.js"; + export * as tsx from "./tsx.tsx.js"; + export * as blank from "./blank.vue.js"; + export * as scriptSetupTS from "./script-setup-ts.vue.js"; + export * as scriptMultiBlock from "./script-multi-block.vue.js"; + export * as ts from "./ts.vue.js"; + " + `); + + expect( + await readFile(resolve(rootDir, "dist/components/ts.vue.d.ts"), "utf8"), + ).toMatchInlineSnapshot(` + "declare const _default: import("vue").DefineComponent<{}, {}, { + test: string; + str: "test"; + }, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; + export default _default; + " + `); + + expect( + await readFile( + resolve(rootDir, "dist/components/blank.vue.d.ts"), + "utf8", + ), + ).toMatchInlineSnapshot(` + "declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; + export default _default; + " + `); + + expect( + await readFile( + resolve(rootDir, "dist/components/script-multi-block.vue.d.ts"), + "utf8", + ), + ).toMatchInlineSnapshot(` + "interface MyComponentProps { + msg: string; + } + declare const _default: import("vue").DefineComponent & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; + export default _default; + " + `); + + expect( + await readFile( + resolve(rootDir, "dist/components/script-setup-ts.vue.d.ts"), + "utf8", + ), + ).toMatchInlineSnapshot(` + "import { Color } from "#prop-types"; + type __VLS_Props = { + msg: string; + color: Color; + }; + declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; + export default _default; + " + `); + + expect(consoleWarnSpy).toHaveBeenCalledWith( + "[mkdist] vue-sfc-transformer is not installed. mkdist will not transform typescript syntax in Vue SFCs.", + ); + expect(consoleWarnSpy).toHaveBeenCalledTimes(1); + }, 50_000); + async function fixture(input: string) { const { loadFile } = createLoader({ loaders: ["vue", "js", "sass"], From aa87bea6eba6dd6415ca40973d93fb0624c47aa7 Mon Sep 17 00:00:00 2001 From: Teages Date: Tue, 8 Apr 2025 23:57:15 +0800 Subject: [PATCH 2/2] test: isolate test environment --- test/index.test.ts | 53 ++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/test/index.test.ts b/test/index.test.ts index da77087..767ba6e 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -10,7 +10,6 @@ import { afterAll, } from "vitest"; import { createLoader } from "../src/loader"; -import { afterEach } from "vitest"; describe("mkdist", () => { let mkdist: typeof import("../src/make").mkdist; @@ -638,12 +637,8 @@ describe("mkdist", () => { }); describe("mkdist with fallback vue loader", () => { - let mkdist: typeof import("../src/make").mkdist; - const consoleWarnSpy = vi.spyOn(console, "warn"); beforeAll(async () => { - mkdist = (await import("../src/make")).mkdist; - vi.resetModules(); vi.doMock("vue-sfc-transformer/mkdist", async () => { throw new Error("vue-sfc-transformer is not installed"); @@ -654,7 +649,7 @@ describe("mkdist with fallback vue loader", () => { vi.doUnmock("vue-sfc-transformer/mkdist"); }); - afterEach(() => { + beforeEach(() => { consoleWarnSpy.mockReset(); }); @@ -722,6 +717,40 @@ describe("mkdist with fallback vue loader", () => { `); }); + async function fixture(input: string) { + const { loadFile } = createLoader({ + loaders: ["vue", "js", "sass"], + }); + const results = await loadFile({ + extension: ".vue", + getContents: () => input, + path: "test.vue", + }); + return results?.[0].contents || input; + } +}); + +describe("mkdist with fallback vue loader (emit types)", () => { + let mkdist: typeof import("../src/make").mkdist; + + const consoleWarnSpy = vi.spyOn(console, "warn"); + beforeAll(async () => { + mkdist = (await import("../src/make")).mkdist; + + vi.resetModules(); + vi.doMock("vue-sfc-transformer/mkdist", async () => { + throw new Error("vue-sfc-transformer is not installed"); + }); + }); + + afterAll(() => { + vi.doUnmock("vue-sfc-transformer/mkdist"); + }); + + beforeEach(() => { + consoleWarnSpy.mockReset(); + }); + it("emit types", async () => { const rootDir = resolve(__dirname, "fixture"); const { writtenFiles } = await mkdist({ @@ -874,18 +903,6 @@ describe("mkdist with fallback vue loader", () => { ); expect(consoleWarnSpy).toHaveBeenCalledTimes(1); }, 50_000); - - async function fixture(input: string) { - const { loadFile } = createLoader({ - loaders: ["vue", "js", "sass"], - }); - const results = await loadFile({ - extension: ".vue", - getContents: () => input, - path: "test.vue", - }); - return results?.[0].contents || input; - } }); describe("mkdist with vue-tsc v1", () => {