Skip to content

Commit

Permalink
feat: resolve npm module type with loader option
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed Jun 12, 2024
1 parent b0837a6 commit 8883000
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 18 deletions.
5 changes: 3 additions & 2 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@
"imports": {
"@deno/cache-dir": "jsr:@deno/cache-dir@^0.8.0",
"@deno/info": "./modules/deno/info.ts",
"@miyauci/esbuild-deno-specifier": "./src/mod.ts",
"@miyauci/format": "jsr:@miyauci/format@^1.1.0",
"@miyauci/node-esm-resolver": "jsr:@miyauci/node-esm-resolver@1.0.0-beta.8",
"@std/collections": "jsr:@std/collections@^0.224.2",
"@std/expect": "jsr:@std/expect@^0.224.2",
"@std/fs": "jsr:@std/fs@^0.229.1",
"@std/log": "jsr:@std/log@^0.224.1",
"@std/path": "jsr:@std/path@^0.225.1",
"@std/testing": "jsr:@std/testing@^0.224.0",
"@std/url": "jsr:@std/url@^0.224.0",
"@unional/path-equal": "jsr:@unional/path-equal@^1.2.5",
"esbuild": "npm:esbuild@^0.21.4",
"@miyauci/esbuild-deno-specifier": "./src/mod.ts"
"esbuild": "npm:esbuild@^0.21.4"
},
"exports": "./src/mod.ts"
}
6 changes: 6 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 11 additions & 5 deletions src/load.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import type { OnLoadResult } from "esbuild";
import type { Loader, OnLoadResult } from "esbuild";
import * as Path from "@std/path/dirname";
import { dirname } from "@std/url/dirname";
import { toFileUrl } from "@std/path/to-file-url";
import { fromFileUrl } from "@std/path/from-file-url";
import type { PluginData } from "./types.ts";
import { mediaTypeToLoader } from "./utils.ts";
import { mediaTypeToLoader, resolveLongestExt } from "./utils.ts";

export async function loadDataURL(
url: URL,
pluginData: PluginData,
): Promise<OnLoadResult> {
const result = await fetch(url);
const contents = await result.text();
const loader = mediaTypeToLoader(pluginData.mediaType);
const loader = pluginData.mediaType &&
mediaTypeToLoader(pluginData.mediaType);

return { contents, loader };
}
Expand All @@ -21,10 +22,14 @@ export async function loadFileURL(
url: URL,
pluginData: PluginData,
readFile: (url: URL) => Promise<string> | string,
loaders: Record<string, Loader>,
): Promise<OnLoadResult> {
const contents = await readFile(url);

const loader = mediaTypeToLoader(pluginData.mediaType);
const loader = pluginData.mediaType
? mediaTypeToLoader(pluginData.mediaType)
: resolveLongestExt(fromFileUrl(url), loaders) ?? "default";

const resolveDir = fromFileUrl(dirname(url));

return { contents, loader, pluginData, resolveDir };
Expand All @@ -48,7 +53,8 @@ export async function loadHttpURL(
const fileUrl = toFileUrl(localPath);
const contents = await readFile(fileUrl);

const loader = mediaTypeToLoader(pluginData.mediaType);
const loader = pluginData.mediaType &&
mediaTypeToLoader(pluginData.mediaType);
const resolveDir = Path.dirname(localPath);

return { contents, loader, pluginData, resolveDir };
Expand Down
9 changes: 3 additions & 6 deletions src/modules/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { require } from "../npm/cjs/require.ts";
import { assertModule, assertModuleEntry } from "./utils.ts";
import type { Subpath } from "../types.ts";
import { Msg } from "../constants.ts";
import { fileFormat } from "../npm/cjs/file_format.ts";
import { resolveSideEffects } from "../side_effects.ts";
import { lookupPackageScope } from "../npm/cjs/lookup_package_scope.ts";

Expand Down Expand Up @@ -182,8 +181,6 @@ export async function toResolveResult(
const finalURL = context.realURL
? (await context.realURL(url)) ?? url
: url;
const format = await fileFormat(finalURL, context);
const mediaType = (format && formatToMediaType(format)) ?? "Unknown";
const packageURL = await lookupPackageScope(finalURL, context);

if (packageURL) {
Expand All @@ -196,15 +193,15 @@ export async function toResolveResult(
fromFileUrl(finalURL),
);

return { url: finalURL, mediaType, sideEffects };
return { url: finalURL, mediaType: undefined, sideEffects };
}
}

return { url: finalURL, mediaType, sideEffects: undefined };
return { url: finalURL, mediaType: undefined, sideEffects: undefined };
}

default: {
return { url, mediaType: "Unknown", sideEffects: undefined };
return { url, mediaType: undefined, sideEffects: undefined };
}
}
}
2 changes: 1 addition & 1 deletion src/modules/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface DependencyContext extends Context {

export interface ResolveResult {
url: URL;
mediaType: MediaType;
mediaType: MediaType | undefined;
sideEffects: boolean | undefined;
}

Expand Down
59 changes: 58 additions & 1 deletion src/option.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { type BuildOptions, type ImportKind, type Platform } from "esbuild";
import {
type BuildOptions,
type ImportKind,
type Loader,
type Platform,
} from "esbuild";

/**
* @see https://esbuild.github.io/api/#resolve-extensions
Expand Down Expand Up @@ -26,6 +31,48 @@ const defaultMainFields = {
*/
const defaultPlatform = "browser" satisfies Platform;

/** Default map of extension and loader.
*
* @see https://esbuild.github.io/content-types/
*/
const defaultContentTypes = {
/**
* @see https://esbuild.github.io/content-types/#javascript
*/
".js": "js",
".mjs": "js",
".cjs": "js",

/**
* @see https://esbuild.github.io/content-types/#typescript
*/
".ts": "ts",
".mts": "ts",
".cts": "ts",

/**
* @see https://esbuild.github.io/content-types/#jsx
*/
".jsx": "jsx",
".tsx": "tsx",

/**
* @see https://esbuild.github.io/content-types/#json
*/
".json": "json",

/**
* @see https://esbuild.github.io/content-types/#css
*/
".css": "css",
".module.css": "local-css",

/**
* @see https://esbuild.github.io/content-types/#text
*/
".txt": "text",
} satisfies Record<string, Loader>;

export function normalizeResolveExtensions(
resolveExtensions?: string[],
): string[] {
Expand Down Expand Up @@ -92,6 +139,15 @@ export function resolvePlatform(platForm: Platform): string | null {
}
}

export function normalizeLoader(
loader?: Record<string, Loader>,
): Record<string, Loader> {
return {
...defaultContentTypes,
...loader,
};
}

export type DependentBuildOptions = Pick<
BuildOptions,
| "platform"
Expand All @@ -101,4 +157,5 @@ export type DependentBuildOptions = Pick<
| "logLevel"
| "packages"
| "absWorkingDir"
| "loader"
>;
5 changes: 4 additions & 1 deletion src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { loadDataURL, loadFileURL, loadHttpURL } from "./load.ts";
import { GlobalStrategy, LocalStrategy } from "./strategy.ts";
import { resolveReferrer } from "./referrer.ts";
import { existDir, existFile, readFile, realURL } from "./io.ts";
import { normalizeLoader } from "./option.ts";

export interface DenoSpecifierPluginOptions {
/** Enables or disables the use of a local node_modules folder for npm packages.
Expand Down Expand Up @@ -139,6 +140,8 @@ export function denoSpecifierPlugin(
},
);

const loader = normalizeLoader(build.initialOptions.loader);

build.onLoad(
{ filter: /.*/, namespace: Namespace.DenoUrl },
(args) => {
Expand All @@ -151,7 +154,7 @@ export function denoSpecifierPlugin(
return loadHttpURL(null, pluginData, readStrict);

case "file:":
return loadFileURL(url, pluginData, readStrict);
return loadFileURL(url, pluginData, readStrict, loader);

case "data:":
return loadDataURL(url, pluginData);
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { MediaType, Module, SourceFileInfo as Source } from "@deno/info";
export interface PluginData {
module: Module;
source: Source;
mediaType: MediaType;
mediaType: MediaType | undefined;
}

export type Subpath = `.${string}`;
Expand Down
39 changes: 39 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { type MediaType } from "@deno/info";
import { toFileUrl } from "@std/path/to-file-url";
import { join } from "@std/url/join";
import { getLogger } from "@std/log/get-logger";
import { runningReduce } from "@std/collections/running-reduce";
import { extname } from "@std/path/extname";
import { type Logger } from "@std/log/logger";

import type { Loader } from "esbuild";
Expand Down Expand Up @@ -102,3 +104,40 @@ export function createNpmRegistryURL(denoDir: string): URL {
export function createPjsonURL(packageURL: URL | string): URL {
return join(packageURL, "package.json");
}

/**
* @param path
* @returns
*/
export function* splitExts(path: string): Generator<string> {
const ext = extname(path);

if (!ext) return;

yield ext;

path = path.slice(0, path.length - ext.length);

yield* splitExts(path);
}

/** Resolve path extension with longest match. */
export function resolveLongestExt<T>(
path: string,
record: Record<string, T>,
): T | undefined {
const allExts = getAllExtensions(path);

for (const ext of allExts) if (ext in record) return record[ext];
}

export function getAllExtensions(path: string): string[] {
const partOfExts = [...splitExts(path)];
const allExts = runningReduce(
partOfExts,
(acc, current) => current + acc,
"",
).reverse();

return allExts;
}
Loading

0 comments on commit 8883000

Please sign in to comment.