diff --git a/README.md b/README.md index 2b303afe..fd487fd9 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,35 @@ console.log(myCode); // Outputs the content of 'example.js' as a string. ``` +### Good News: + +With the latest update, you no longer need to specify the file extension explicitly. + +```js +import myCode from "./example?raw"; +``` + +This works seamlessly! Additionally, if you're exporting from files like `index.tsx`, `index.jsx`, etc., you can simplify imports. For example, if your file path is `my-lib/index.ts`, you can import the raw content like this: + +```js +import myCode from "./my-lib?raw"; +``` + +### Extension Options (Optional) + +```ts +export interface RawPluginOptions { + /** + * Extensions to check in order if the file does not exist. + * If it's a directory, the plugin will look for `dir/index.[ext]`. + * @defaultValue ["tsx", "ts", "jsx", "js", "mjs", "mts", "module.css", "module.scss", "css", "scss"] + * + * You can provide your own extensions to optimize build performance or extend the list based on your use case. + */ + ext?: string[]; +} +``` + ### Supported File Types You can use `?raw` with any file type, including: diff --git a/lib/CHANGELOG.md b/lib/CHANGELOG.md new file mode 100644 index 00000000..e2d12347 --- /dev/null +++ b/lib/CHANGELOG.md @@ -0,0 +1,7 @@ +# esbuild-raw-plugin + +## 0.1.0 + +### Minor Changes + +- 8a7e550: Autocomplete extensions if not added in import statement. diff --git a/lib/__tests__/index.test.ts b/lib/__tests__/index.test.ts index fc7618cd..a2ccdd1e 100644 --- a/lib/__tests__/index.test.ts +++ b/lib/__tests__/index.test.ts @@ -1,27 +1,45 @@ import { beforeAll, describe, test } from "vitest"; -import esbuild from "esbuild"; +import esbuild, { BuildOptions } from "esbuild"; import path from "node:path"; import { raw } from "../src"; import fs from "node:fs"; +const buildOptions: BuildOptions = { + format: "cjs", + target: "es2019", + sourcemap: false, + bundle: true, + minify: true, + entryPoints: [path.resolve(__dirname, "test.ts")], + outdir: "__tests__/dist", + treeShaking: true, + plugins: [raw()], +}; + describe("WebGL plugins", () => { - beforeAll(async () => { - await esbuild.build({ - format: "cjs", - target: "es2019", - sourcemap: false, - bundle: true, - minify: true, - entryPoints: [path.resolve(__dirname, "test.ts")], - outdir: "__tests__/dist", - treeShaking: true, - plugins: [raw()], - }); - }); test("test raw import", async ({ expect }) => { + await esbuild.build(buildOptions); const fileContent = fs.readFileSync(path.resolve(__dirname, "../src/index.ts"), "utf-8"); // @ts-ignore const generatedCodeContent = (await import("./dist/test.js")).getText(); expect(fileContent).toBe(generatedCodeContent); }); + + test("test raw import with auto ext", async ({ expect }) => { + await esbuild.build({ ...buildOptions, entryPoints: [path.resolve(__dirname, "test1.ts")] }); + const fileContent = fs.readFileSync(path.resolve(__dirname, "../src/index.ts"), "utf-8"); + // @ts-ignore + const generatedCodeContent = (await import("./dist/test1.js")).getText(); + expect(fileContent).toBe(generatedCodeContent); + }); + + test("throws error if no file is found", async ({ expect }) => { + let didThrow = false; + try { + await esbuild.build({ ...buildOptions, entryPoints: [path.resolve(__dirname, "test2.ts")] }); + } catch (e) { + didThrow = true; + } + expect(didThrow).toBe(true); + }); }); diff --git a/lib/__tests__/test1.ts b/lib/__tests__/test1.ts new file mode 100644 index 00000000..4f2e2232 --- /dev/null +++ b/lib/__tests__/test1.ts @@ -0,0 +1,5 @@ +// test auto complete + +import text from "../src?raw"; + +export const getText = () => text; diff --git a/lib/__tests__/test2.ts b/lib/__tests__/test2.ts new file mode 100644 index 00000000..ad640664 --- /dev/null +++ b/lib/__tests__/test2.ts @@ -0,0 +1,5 @@ +// test auto error + +import text from "../src/my-file?raw"; + +export const getText = () => text; diff --git a/lib/package.json b/lib/package.json index 7c03cc8b..5c2f26fd 100644 --- a/lib/package.json +++ b/lib/package.json @@ -2,7 +2,7 @@ "name": "esbuild-raw-plugin", "author": "Mayank Kumar Chaudhari ", "private": false, - "version": "0.0.0", + "version": "0.1.0", "description": "An ESBuild and TSUP plugin that allows importing files as raw text. Useful for loading code files in documentation, interactive demos, or tools like react-live.", "license": "MPL-2.0", "main": "./dist/index.js", diff --git a/lib/src/index.ts b/lib/src/index.ts index 197953c7..1b3e5c50 100644 --- a/lib/src/index.ts +++ b/lib/src/index.ts @@ -2,11 +2,34 @@ import type { Plugin, PluginBuild } from "esbuild"; import fs from "node:fs"; import path from "node:path"; +export interface RawPluginOptions { + /** + * Extensions to check in order if the file does not exist. + * If it's a directory, the plugin will look for `dir/index.[ext]`. + * @defaultValue ["tsx", "ts", "jsx", "js", "mjs", "mts", "module.css", "module.scss", "css", "scss"] + * + * You can provide your own extensions to optimize build performance or extend the list based on your use case. + */ + ext?: string[]; +} + /** Plugin to load `.glsl` files as minified strings */ -export const raw: () => Plugin = () => ({ +export const raw: (options?: RawPluginOptions) => Plugin = options => ({ /** generate randmo name to avoid collision among the plugins */ name: `raw-${(Date.now() * Math.random()).toString(36).slice(0, 8)}`, setup(build: PluginBuild) { + const ext = options?.ext ?? [ + "tsx", + "ts", + "jsx", + "js", + "mjs", + "mts", + "module.css", + "module.scss", + "css", + "scss", + ]; build.onResolve({ filter: /\?raw$/ }, args => { const filePath = args.path; return { @@ -15,9 +38,23 @@ export const raw: () => Plugin = () => ({ namespace: "raw", }; }); - build.onLoad({ filter: /\?raw$/, namespace: "raw" }, async args => { + build.onLoad({ filter: /\?raw$/, namespace: "raw" }, args => { + let filePath = args.pluginData; + if (fs.lstatSync(filePath).isDirectory()) filePath += path.sep + "index"; + if (!fs.existsSync(filePath)) + for (const e of ext) + if (fs.existsSync(filePath + "." + e)) { + filePath += "." + e; + break; + } + if (!fs.existsSync(filePath)) + throw new Error( + /* v8 ignore next */ + `File not found: ${args.pluginData}\nWe checked for following extensions: ${ext.join(", ")}. You can customise by passing {ext: [...]} to raw({ext:[...]})`, + /* v8 ignore next */ + ); return { - contents: fs.readFileSync(args.pluginData, "utf8"), + contents: fs.readFileSync(filePath, "utf8"), loader: "text", }; }); diff --git a/packages/shared/CHANGELOG.md b/packages/shared/CHANGELOG.md new file mode 100644 index 00000000..96e554d3 --- /dev/null +++ b/packages/shared/CHANGELOG.md @@ -0,0 +1,8 @@ +# @repo/shared + +## 0.0.1 + +### Patch Changes + +- Updated dependencies [8a7e550] + - esbuild-raw-plugin@0.1.0 diff --git a/packages/shared/package.json b/packages/shared/package.json index 1b2d0bdf..90338e08 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@repo/shared", - "version": "0.0.0", + "version": "0.0.1", "private": true, "sideEffects": false, "main": "./dist/index.js",