Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalize file paths for require context on Windows #876

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ exports[`getContextModuleTemplate creates a lazy template 1`] = `
const map = Object.defineProperties({}, {
\\"./foo.js\\": { enumerable: true, get() { return import(\\"/path/to/project/src/foo.js\\"); } },
});

function metroContext(request) {
return map[request];
}

// Return the keys that can be resolved.
metroContext.keys = function metroContextKeys() {
return Object.keys(map);
Expand All @@ -29,11 +29,11 @@ const map = Object.defineProperties({}, {
\\"./another/bar.js\\": { enumerable: true, get() { return import(\\"/path/to/project/src/another/bar.js\\"); } },
\\"./foo.js\\": { enumerable: true, get() { return import(\\"/path/to/project/src/foo.js\\"); } },
});

function metroContext(request) {
return map[request];
}

// Return the keys that can be resolved.
metroContext.keys = function metroContextKeys() {
return Object.keys(map);
Expand All @@ -52,11 +52,11 @@ exports[`getContextModuleTemplate creates a sync template 1`] = `
const map = Object.defineProperties({}, {
\\"./foo.js\\": { enumerable: true, get() { return require(\\"/path/to/project/src/foo.js\\"); } },
});

function metroContext(request) {
return map[request];
}

// Return the keys that can be resolved.
metroContext.keys = function metroContextKeys() {
return Object.keys(map);
Expand All @@ -75,13 +75,13 @@ exports[`getContextModuleTemplate creates an eager template 1`] = `
const map = Object.defineProperties({}, {
\\"./foo.js\\": { enumerable: true, get() { return require(\\"/path/to/project/src/foo.js\\"); } },
});

function metroContext(request) {
// Here Promise.resolve().then() is used instead of new Promise() to prevent
// uncaught exception popping up in devtools
return Promise.resolve().then(() => map[request]);
}

// Return the keys that can be resolved.
metroContext.keys = function metroContextKeys() {
return Object.keys(map);
Expand Down Expand Up @@ -113,3 +113,26 @@ metroEmptyContext.resolve = function metroContextResolve(request) {

module.exports = metroEmptyContext;"
`;

exports[`getContextModuleTemplate creates posix paths on windows for sync template 1`] = `
"// All of the requested modules are loaded behind enumerable getters.
const map = Object.defineProperties({}, {
\\"./foo.js\\": { enumerable: true, get() { return require(\\"C:\\\\\\\\path\\\\\\\\to\\\\\\\\project\\\\\\\\src\\\\\\\\foo.js\\"); } },
});

function metroContext(request) {
return map[request];
}

// Return the keys that can be resolved.
metroContext.keys = function metroContextKeys() {
return Object.keys(map);
};

// Return the module identifier for a user request.
metroContext.resolve = function metroContextResolve(request) {
throw new Error('Unimplemented Metro module context functionality');
}

module.exports = metroContext;"
`;
13 changes: 13 additions & 0 deletions packages/metro/src/lib/__tests__/contextModuleTemplates-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,17 @@ describe('getContextModuleTemplate', () => {

expect(template).toMatchSnapshot();
});

test('creates posix paths on windows for sync template', () => {
jest.resetModules();
jest.mock('path', () => jest.requireActual('path').win32);
const {
getContextModuleTemplate: getWindowsTemplate,
} = require('../contextModuleTemplates');
const template = getWindowsTemplate('sync', 'c:/path/to/project/src', [
'C:\\path\\to\\project\\src\\foo.js',
]);
expect(template).toMatch(/foo\.js/);
expect(template).toMatchSnapshot();
});
});
12 changes: 9 additions & 3 deletions packages/metro/src/lib/contextModuleTemplates.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*/

import * as path from 'path';
import * as os from 'os';
import type {ContextMode} from '../ModuleGraph/worker/collectDependencies';

function createFileMap(
Expand All @@ -26,14 +27,19 @@ function createFileMap(
.forEach(file => {
let filePath = path.relative(modulePath, file);

if (os.platform() === 'win32') {
filePath = filePath.replace(/\\/g, '/');
}

// NOTE(EvanBacon): I'd prefer we prevent the ability for a module to require itself (`require.context('./')`)
// but Webpack allows this, keeping it here provides better parity between bundlers.

// Ensure relative file paths start with `./` so they match the
// patterns (filters) used to include them.
if (!filePath.startsWith('.')) {
filePath = `.${path.sep}` + filePath;
filePath = `./${filePath}`;
}

const key = JSON.stringify(filePath);
// NOTE(EvanBacon): Webpack uses `require.resolve` in order to load modules on demand,
// Metro doesn't have this functionality so it will use getters instead. Modules need to
Expand Down Expand Up @@ -79,11 +85,11 @@ const map = ${createFileMap(
files,
moduleId => `${importSyntax}(${JSON.stringify(moduleId)})`,
)};

function metroContext(request) {
${getContextTemplate}
}

// Return the keys that can be resolved.
metroContext.keys = function metroContextKeys() {
return Object.keys(map);
Expand Down