Skip to content

Commit

Permalink
Use alternative implementation for __dirname
Browse files Browse the repository at this point in the history
  • Loading branch information
Mrtenz committed Feb 27, 2024
1 parent 2752834 commit 524a68f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 45 deletions.
8 changes: 4 additions & 4 deletions packages/snaps-utils/coverage.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"branches": 96.46,
"functions": 98.63,
"lines": 98.55,
"statements": 94.33
"branches": 96.44,
"functions": 98.62,
"lines": 98.74,
"statements": 94.48
}
35 changes: 6 additions & 29 deletions packages/snaps-utils/src/eval.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { assert } from '@metamask/utils';
import { fork } from 'child_process';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { join } from 'path';

import { validateFilePath } from './fs';

Expand All @@ -21,22 +20,6 @@ export class SnapEvalError extends Error {
}
}

/**
* Get the dirname of the file at the provided `import.meta.url`. This is
* similar to `__dirname` in CommonJS modules.
*
* @param importMetaUrl - The `import.meta.url` of the file to get the dirname
* of.
* @returns The dirname of the file at the provided `import.meta.url`.
*/
export function getDirname(importMetaUrl: string): string {
if (importMetaUrl.startsWith('file://')) {
return dirname(fileURLToPath(importMetaUrl));
}

return dirname(importMetaUrl);
}

/**
* Spawn a new process to run the provided bundle in.
*
Expand All @@ -48,17 +31,11 @@ export async function evalBundle(bundlePath: string): Promise<EvalOutput> {
await validateFilePath(bundlePath);

return new Promise((resolve, reject) => {
const worker = fork(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - `import.meta` is not supported in the current environment.
join(getDirname(import.meta.url), 'eval-worker.js'),
[bundlePath],
{
// To avoid printing the output of the worker to the console, we set
// `stdio` to `pipe` and handle the output ourselves.
stdio: 'pipe',
},
);
const worker = fork(join(__dirname, 'eval-worker.js'), [bundlePath], {
// To avoid printing the output of the worker to the console, we set
// `stdio` to `pipe` and handle the output ourselves.
stdio: 'pipe',
});

let stdout = '';
let stderr = '';
Expand Down
52 changes: 40 additions & 12 deletions tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
import { builtinModules } from 'module';
import type { Options } from 'tsup';

// `Plugin` is not exported from `tsup`, so we have to define it ourselves.
type Plugin = Options['plugins'][number];

const DIRNAME_SHIM = `import { fileURLToPath } from 'url'
import path from 'path'
const getFilename = () => fileURLToPath(import.meta.url)
const getDirname = () => path.dirname(getFilename())
export const __dirname = /* @__PURE__ */ getDirname()`;

/**
* A `tsup` plugin that adds a `__dirname` shim to the beginning of each chunk
* that uses `__dirname`. This is necessary because `__dirname` is not available
* in ESM, so we have to use `import.meta.url` and `fileURLToPath` to get the
* dirname of the current file.
*
* Note: This breaks source maps in the files that use `__dirname`.
*/
const dirnameShimPlugin: Plugin = {
name: 'dirname-shim-plugin',

renderChunk(code, info) {
if (
info.type !== 'chunk' ||
this.format === 'cjs' ||
!code.includes('__dirname')
) {
return undefined;
}

// Not sure how this impacts source maps
return { code: `${DIRNAME_SHIM}\n${code}`, map: info.map };
},
};

const config: Options = {
// Clean the dist folder before bundling.
clean: true,
Expand Down Expand Up @@ -32,6 +68,10 @@ const config: Options = {
// the bundles will work in both Node.js and browsers.
platform: 'neutral',

// The plugins to use when bundling. We add a plugin that adds a `__dirname`
// shim to the beginning of each chunk that uses `__dirname`.
plugins: [dirnameShimPlugin],

// Hide unnecessary logs from the console. Warnings and errors will still be
// shown.
silent: true,
Expand All @@ -43,18 +83,6 @@ const config: Options = {
// Split the output into chunks. This is useful for tree-shaking.
// https://tsup.egoist.dev/#code-splitting
splitting: true,

esbuildOptions: (options, { format }) => {
if (format === 'cjs') {
options.define = {
// Using `import.meta` in Node.js without ESM is a syntax error, so
// we replace `import.meta.url` with `__filename` in CommonJS bundles.
// This only works with the `getDirname` function in `snaps-utils`.
// eslint-disable-next-line @typescript-eslint/naming-convention
'import.meta.url': '__filename',
};
}
},
};

export default config;

0 comments on commit 524a68f

Please sign in to comment.