diff --git a/src/client.d.ts b/src/client.d.ts new file mode 100644 index 00000000..b45185b4 --- /dev/null +++ b/src/client.d.ts @@ -0,0 +1,4 @@ +declare module '*?raw' { + const value: string + export default value +} diff --git a/src/esbuild/import-raw.ts b/src/esbuild/import-raw.ts new file mode 100644 index 00000000..d4031f2d --- /dev/null +++ b/src/esbuild/import-raw.ts @@ -0,0 +1,24 @@ +import { readFile } from 'fs/promises' +import type { Plugin } from 'esbuild' +import { join } from 'path' + +/** + * Importing a resource as a string + */ +export const importRawPlugin = (): Plugin => { + return { + name: 'importRawPlugin', + setup(build) { + const rawReg = /(?:\?|&)raw(?:&|$)/ + build.onResolve({ filter: rawReg }, (args) => { + const { resolveDir, path } = args + return { path: join(resolveDir, path) } + }) + build.onLoad({ filter: rawReg }, async (args) => { + const path = args.path.replace(rawReg, '') + const content = await readFile(path, 'utf-8') + return { contents: JSON.stringify(content), loader: 'text' } + }) + }, + } +} diff --git a/src/esbuild/index.ts b/src/esbuild/index.ts index aec991d0..569e2a5c 100644 --- a/src/esbuild/index.ts +++ b/src/esbuild/index.ts @@ -19,6 +19,7 @@ import { swcPlugin } from './swc' import { nativeNodeModulesPlugin } from './native-node-module' import { PluginContainer } from '../plugin' import { OutExtensionFactory } from '../options' +import { importRawPlugin } from './import-raw' const getOutputExtensionMap = ( options: NormalizedOptions, @@ -146,6 +147,7 @@ export async function runEsbuild( cssLoader: loader['.css'], }), sveltePlugin({ css }), + importRawPlugin(), ...(options.esbuildPlugins || []), ] diff --git a/test/index.test.ts b/test/index.test.ts index fcbc1782..61f025f1 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1345,9 +1345,14 @@ test('should emit a declaration file per format', async () => { format: ['esm', 'cjs'], dts: true }`, - }); - expect(outFiles).toEqual(['input.d.mts', 'input.d.ts', 'input.js', 'input.mjs']) -}); + }) + expect(outFiles).toEqual([ + 'input.d.mts', + 'input.d.ts', + 'input.js', + 'input.mjs', + ]) +}) test('should emit a declaration file per format (type: module)', async () => { const { outFiles } = await run(getTestName(), { @@ -1361,6 +1366,38 @@ test('should emit a declaration file per format (type: module)', async () => { format: ['esm', 'cjs'], dts: true }`, - }); - expect(outFiles).toEqual(['input.cjs', 'input.d.cts', 'input.d.ts', 'input.js']) -}); + }) + expect(outFiles).toEqual([ + 'input.cjs', + 'input.d.cts', + 'input.d.ts', + 'input.js', + ]) +}) + +test('should importing a resource as a string', async () => { + const { outFiles } = await run(getTestName(), { + 'input.ts': ` + import fragText from "./frag.glsl?raw" + console.log(fragText) + `, + 'frag.glsl': `void main() { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + }`, + 'package.json': `{ + "type": "module" + }`, + 'tsup.config.ts': ` + export default { + entry: ['src/input.ts'], + format: ['esm', 'cjs'], + dts: true + }`, + }) + expect(outFiles).toEqual([ + 'input.cjs', + 'input.d.cts', + 'input.d.ts', + 'input.js', + ]) +})