Skip to content

Commit

Permalink
Correctly resolve module exports when running crackle dev (#129)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrm007 authored Jul 28, 2023
1 parent 433a30f commit 2b57d2f
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 44 deletions.
7 changes: 7 additions & 0 deletions .changeset/dev-entries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@crackle/core': patch
---

Correctly resolve module exports when running `crackle dev`

This fixes an issue where `crackle dev` would not resolve an entry's exports when the entry re-exported from another module using `export * from ...` syntax.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ fixtures/braid-site/dist
# managed by crackle
fixtures/dev-entries/cli
fixtures/dev-entries/dist
fixtures/dev-entries/re-export
# end managed by crackle

# managed by crackle
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ fixtures/braid-site/dist
# managed by crackle
fixtures/dev-entries/cli
fixtures/dev-entries/dist
fixtures/dev-entries/re-export
# end managed by crackle

# managed by crackle
Expand Down
1 change: 1 addition & 0 deletions fixtures/dev-entries/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# managed by crackle
/cli
/dist
/re-export
# end managed by crackle
8 changes: 7 additions & 1 deletion fixtures/dev-entries/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@
"import": "./dist/cli.mjs",
"require": "./dist/cli.cjs"
},
"./re-export": {
"types": "./dist/re-export.d.ts",
"import": "./dist/re-export.mjs",
"require": "./dist/re-export.cjs"
},
"./package.json": "./package.json"
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"cli",
"dist"
"dist",
"re-export"
],
"scripts": {
"dev": "crackle dev",
Expand Down
1 change: 1 addition & 0 deletions fixtures/dev-entries/src/entries/re-export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../';
2 changes: 0 additions & 2 deletions packages/core/src/entries/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import { commonViteConfig } from '../vite-config';
import { logger } from './logger';
import { pageGlobSuffix } from './route-data';

export * from '../types';

type Socket = http.IncomingMessage['socket'];

export const start = async (
Expand Down
91 changes: 53 additions & 38 deletions packages/core/src/utils/entry-points.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,47 @@ import {
getPackageEntryPoints,
} from './entry-points';

const root = '/___';
const volume = {
[`${root}/src/index.ts`]: 'export default {}',
[`${root}/src/entries/components.ts`]: 'export const components = {}',
[`${root}/src/entries/extras.ts`]: 'export const extras = {}',
[`${root}/src/entries/themes/apac.ts`]: 'export default {}',
};

vi.mock('fs', () => ({ default: fs }));
vi.mock('fs/promises', () => ({ default: fs.promises }));
vi.mock('fs-extra', () => ({ default: { ...fs, ...fs.promises } }));
vi.mock('mlly', () => ({
resolveModuleExportNames: (filePath: string) => {
// This is not ideal, but refactoring to use the real file system (and make it work with snapshots) would be a lot of work.
// Besides, we have an integration test covering this scenario.
switch (filePath) {
case `${root}/src/index.ts`:
return Promise.resolve(['default']);
case `${root}/src/entries/components.ts`:
return Promise.resolve(['components']);
case `${root}/src/entries/extras.ts`:
return Promise.resolve(['extras']);
case `${root}/src/entries/themes/apac.ts`:
return Promise.resolve(['default']);
default:
throw new Error(`Not mocked: ${filePath}`);
}
},
}));

describe('getPackageEntryPoints', () => {
const packageRoot = '/___';

beforeEach(() => {
vol.reset();
vol.fromJSON(
{
'src/index.ts': 'export default {}',
'src/entries/components.ts': 'export const components = {}',
'src/entries/extras.ts': 'export const extras = {}',
'src/entries/themes/apac.ts': 'export default {}',
},
packageRoot,
);
vol.fromJSON(volume);

context.enterWith({
root: packageRoot,
root,
} as EnhancedConfig);
});

test('all entry points', async () => {
const entryPoints = await getPackageEntryPoints(packageRoot);
const entryPoints = await getPackageEntryPoints(root);

expect(entryPoints).toMatchInlineSnapshot(`
[
Expand Down Expand Up @@ -75,7 +90,7 @@ describe('getPackageEntryPoints', () => {
});

test('getOutputPath for index', async () => {
const entryPoints = await getPackageEntryPoints(packageRoot);
const entryPoints = await getPackageEntryPoints(root);
const entry = entryPoints.find(({ isDefaultEntry }) => isDefaultEntry)!;

expect(entry.getOutputPath('esm')).toMatchInlineSnapshot('"index.mjs"');
Expand All @@ -84,22 +99,22 @@ describe('getPackageEntryPoints', () => {
});

test('getOutputPath (from root) for index', async () => {
const entryPoints = await getPackageEntryPoints(packageRoot);
const entryPoints = await getPackageEntryPoints(root);
const entry = entryPoints.find(({ isDefaultEntry }) => isDefaultEntry)!;

expect(
entry.getOutputPath('esm', { from: packageRoot }),
).toMatchInlineSnapshot('"dist/index.mjs"');
expect(
entry.getOutputPath('cjs', { from: packageRoot }),
).toMatchInlineSnapshot('"dist/index.cjs"');
expect(
entry.getOutputPath('dts', { from: packageRoot }),
).toMatchInlineSnapshot('"dist/index.d.ts"');
expect(entry.getOutputPath('esm', { from: root })).toMatchInlineSnapshot(
'"dist/index.mjs"',
);
expect(entry.getOutputPath('cjs', { from: root })).toMatchInlineSnapshot(
'"dist/index.cjs"',
);
expect(entry.getOutputPath('dts', { from: root })).toMatchInlineSnapshot(
'"dist/index.d.ts"',
);
});

test('getOutputPath for entry', async () => {
const entryPoints = await getPackageEntryPoints(packageRoot);
const entryPoints = await getPackageEntryPoints(root);
const entry = entryPoints.find(({ isDefaultEntry }) => !isDefaultEntry)!;

expect(entry.getOutputPath('esm')).toMatchInlineSnapshot(
Expand All @@ -114,22 +129,22 @@ describe('getPackageEntryPoints', () => {
});

test('getOutputPath (from root) for entry', async () => {
const entryPoints = await getPackageEntryPoints(packageRoot);
const entryPoints = await getPackageEntryPoints(root);
const entry = entryPoints.find(({ isDefaultEntry }) => !isDefaultEntry)!;

expect(
entry.getOutputPath('esm', { from: packageRoot }),
).toMatchInlineSnapshot('"dist/components.mjs"');
expect(
entry.getOutputPath('cjs', { from: packageRoot }),
).toMatchInlineSnapshot('"dist/components.cjs"');
expect(
entry.getOutputPath('dts', { from: packageRoot }),
).toMatchInlineSnapshot('"dist/components.d.ts"');
expect(entry.getOutputPath('esm', { from: root })).toMatchInlineSnapshot(
'"dist/components.mjs"',
);
expect(entry.getOutputPath('cjs', { from: root })).toMatchInlineSnapshot(
'"dist/components.cjs"',
);
expect(entry.getOutputPath('dts', { from: root })).toMatchInlineSnapshot(
'"dist/components.d.ts"',
);
});

test('createEntryPackageJsons', async () => {
const entryPoints = await getPackageEntryPoints(packageRoot);
const entryPoints = await getPackageEntryPoints(root);

await createEntryPackageJsons(entryPoints);

Expand Down Expand Up @@ -169,7 +184,7 @@ describe('getPackageEntryPoints', () => {
});

test('cleanPackageEntryPoints', async () => {
const entryPoints = await getPackageEntryPoints(packageRoot);
const entryPoints = await getPackageEntryPoints(root);
await createEntryPackageJsons(entryPoints);

await cleanPackageEntryPoints(entryPoints);
Expand Down
10 changes: 7 additions & 3 deletions packages/core/src/utils/entry-points.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import fs from 'fs';
import path from 'path';
import { pathToFileURL } from 'url';

import dedent from 'dedent';
import glob from 'fast-glob';
import { findExportNames } from 'mlly';
import { resolveModuleExportNames } from 'mlly';

import { getConfigFromContext, type EnhancedConfig } from '../config';
import { distDir } from '../constants';
Expand All @@ -28,8 +29,11 @@ export type Packages = Map<string, Package>;
export const getExports = async (filePath: string) => {
const config = getConfigFromContext();

const fileContents = await fs.promises.readFile(filePath, 'utf-8');
const exports = findExportNames(fileContents);
const exports = await resolveModuleExportNames(filePath, {
url: pathToFileURL(filePath),
extensions: ['.js', '.ts', '.tsx'],
});

logger.debug(dedent`
[getExports]
filePath: ${path.relative(config.root, filePath)}
Expand Down
25 changes: 25 additions & 0 deletions tests/__snapshots__/dev/dev-entries/dist/re-export.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* #region dist/re-export.cjs */
require("../../../node_modules/.pnpm/[email protected]/node_modules/tsm/require.js");

module.exports = require("../src/entries/re-export.ts");
/* #endregion */


/* #region dist/re-export.d.ts */
export * from "../src/entries/re-export";
export { default } from "../src/entries/re-export";
/* #endregion */


/* #region dist/re-export.mjs */
import { createRequire } from "module";

const require = createRequire(import.meta.url);

require("../../../node_modules/.pnpm/[email protected]/node_modules/tsm/require.js");

const _mod = require("../src/entries/re-export.ts");

export const something = _mod.something;
export default _mod.default;
/* #endregion */

0 comments on commit 2b57d2f

Please sign in to comment.