mirror of https://github.com/status-im/metro.git
Convert entryPoint paths to absolute in the Server
Reviewed By: davidaurelio Differential Revision: D7196392 fbshipit-source-id: a1927d66fd67e35382a5ac418896dc5a902a5a5c
This commit is contained in:
parent
ab25e7c475
commit
40cce3b120
|
@ -11,6 +11,8 @@
|
|||
'use strict';
|
||||
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const process = require('process');
|
||||
|
||||
const {EventEmitter} = require('events');
|
||||
|
||||
|
@ -33,6 +35,7 @@ export type LogEntry = {
|
|||
action_name?: string,
|
||||
action_phase?: string,
|
||||
duration_ms?: number,
|
||||
entry_point?: string,
|
||||
log_entry_label: string,
|
||||
log_session?: string,
|
||||
start_timestamp?: [number, number],
|
||||
|
@ -46,7 +49,13 @@ function on(event: string, handler: (logEntry: LogEntry) => void): void {
|
|||
}
|
||||
|
||||
function createEntry(data: LogEntry | string): LogEntry {
|
||||
const logEntry = typeof data === 'string' ? {log_entry_label: data} : data;
|
||||
const logEntry: LogEntry =
|
||||
typeof data === 'string' ? {log_entry_label: data} : data;
|
||||
|
||||
const entryPoint = logEntry.entry_point;
|
||||
if (entryPoint) {
|
||||
logEntry.entry_point = path.relative(process.cwd(), entryPoint);
|
||||
}
|
||||
|
||||
return {
|
||||
...logEntry,
|
||||
|
|
|
@ -73,13 +73,9 @@ class DeltaCalculator extends EventEmitter {
|
|||
this._options = options;
|
||||
this._dependencyGraph = dependencyGraph;
|
||||
|
||||
const entryPoints = this._options.entryPoints.map(entryPoint =>
|
||||
this._dependencyGraph.getAbsolutePath(entryPoint),
|
||||
);
|
||||
|
||||
this._graph = {
|
||||
dependencies: new Map(),
|
||||
entryPoints,
|
||||
entryPoints: this._options.entryPoints,
|
||||
};
|
||||
|
||||
this._dependencyGraph
|
||||
|
|
|
@ -356,19 +356,12 @@ class DeltaTransformer extends EventEmitter {
|
|||
}
|
||||
|
||||
async _getAppend(dependencyEdges: DependencyEdges): Promise<DeltaEntries> {
|
||||
// Get the absolute path of the entry file, in order to be able to get the
|
||||
// actual correspondant module (and its moduleId) to be able to add the
|
||||
// correct require(); call at the very end of the bundle.
|
||||
const entryPointModulePath = this._dependencyGraph.getAbsolutePath(
|
||||
this._bundleOptions.entryFile,
|
||||
);
|
||||
|
||||
// First, get the modules correspondant to all the module names defined in
|
||||
// the `runBeforeMainModule` config variable. Then, append the entry point
|
||||
// module so the last thing that gets required is the entry point.
|
||||
const append = new Map(
|
||||
this._bundleOptions.runBeforeMainModule
|
||||
.concat(entryPointModulePath)
|
||||
.concat(this._bundleOptions.entryFile)
|
||||
.filter(path => dependencyEdges.has(path))
|
||||
.map(this._getModuleId)
|
||||
.map(moduleId => {
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
jest.mock('../../lib/getAbsolutePath');
|
||||
|
||||
const HmrServer = require('..');
|
||||
|
||||
const {EventEmitter} = require('events');
|
||||
|
@ -41,6 +43,9 @@ describe('HmrServer', () => {
|
|||
update: jest.fn(),
|
||||
};
|
||||
},
|
||||
getProjectRoots() {
|
||||
return ['/root'];
|
||||
},
|
||||
};
|
||||
|
||||
hmrServer = new HmrServer(serverMock);
|
||||
|
@ -57,7 +62,7 @@ describe('HmrServer', () => {
|
|||
expect.objectContaining({
|
||||
deltaBundleId: null,
|
||||
dev: true,
|
||||
entryFile: 'EntryPoint.js',
|
||||
entryFile: '/root/EntryPoint.js',
|
||||
minify: false,
|
||||
platform: 'ios',
|
||||
}),
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
const addParamsToDefineCall = require('../lib/addParamsToDefineCall');
|
||||
const formatBundlingError = require('../lib/formatBundlingError');
|
||||
const getAbsolutePath = require('../lib/getAbsolutePath');
|
||||
const getBundlingOptionsForHmr = require('./getBundlingOptionsForHmr');
|
||||
const nullthrows = require('fbjs/lib/nullthrows');
|
||||
const parseCustomTransformOptions = require('../lib/parseCustomTransformOptions');
|
||||
|
@ -66,7 +67,11 @@ class HmrServer<TClient: Client> {
|
|||
const deltaBundler = this._packagerServer.getDeltaBundler();
|
||||
const deltaTransformer = await deltaBundler.getDeltaTransformer(
|
||||
clientUrl,
|
||||
getBundlingOptionsForHmr(bundleEntry, platform, customTransformOptions),
|
||||
getBundlingOptionsForHmr(
|
||||
getAbsolutePath(bundleEntry, this._packagerServer.getProjectRoots()),
|
||||
platform,
|
||||
customTransformOptions,
|
||||
),
|
||||
);
|
||||
|
||||
// Trigger an initial build to start up the DeltaTransformer.
|
||||
|
|
|
@ -21,6 +21,7 @@ jest
|
|||
.mock('../../Assets')
|
||||
.mock('../../node-haste/DependencyGraph')
|
||||
.mock('metro-core/src/Logger')
|
||||
.mock('../../lib/getAbsolutePath')
|
||||
.mock('../../lib/GlobalTransformCache')
|
||||
.mock('../../DeltaBundler/Serializers/Serializers');
|
||||
|
||||
|
@ -47,7 +48,7 @@ describe('processRequest', () => {
|
|||
let server;
|
||||
|
||||
const options = {
|
||||
projectRoots: ['root'],
|
||||
projectRoots: ['/root'],
|
||||
blacklistRE: null,
|
||||
cacheVersion: null,
|
||||
polyfillModuleNames: null,
|
||||
|
@ -183,7 +184,7 @@ describe('processRequest', () => {
|
|||
bundleType: 'bundle',
|
||||
customTransformOptions: {},
|
||||
dev: true,
|
||||
entryFile: 'index.ios.js',
|
||||
entryFile: '/root/index.ios.js',
|
||||
entryModuleOnly: false,
|
||||
excludeSource: false,
|
||||
hot: true,
|
||||
|
@ -214,7 +215,7 @@ describe('processRequest', () => {
|
|||
bundleType: 'bundle',
|
||||
customTransformOptions: {},
|
||||
dev: true,
|
||||
entryFile: 'index.js',
|
||||
entryFile: '/root/index.js',
|
||||
entryModuleOnly: false,
|
||||
excludeSource: false,
|
||||
hot: true,
|
||||
|
@ -245,7 +246,7 @@ describe('processRequest', () => {
|
|||
bundleType: 'bundle',
|
||||
customTransformOptions: {},
|
||||
dev: true,
|
||||
entryFile: 'index.js',
|
||||
entryFile: '/root/index.js',
|
||||
entryModuleOnly: false,
|
||||
excludeSource: false,
|
||||
hot: true,
|
||||
|
@ -391,7 +392,7 @@ describe('processRequest', () => {
|
|||
|
||||
server.processRequest(req, res);
|
||||
res.end.mockImplementation(value => {
|
||||
expect(getAsset).toBeCalledWith('imgs/a.png', ['root'], 'ios');
|
||||
expect(getAsset).toBeCalledWith('imgs/a.png', ['/root'], 'ios');
|
||||
expect(value).toBe('i am image');
|
||||
done();
|
||||
});
|
||||
|
@ -409,7 +410,7 @@ describe('processRequest', () => {
|
|||
|
||||
server.processRequest(req, res);
|
||||
res.end.mockImplementation(value => {
|
||||
expect(getAsset).toBeCalledWith('imgs/a.png', ['root'], 'ios');
|
||||
expect(getAsset).toBeCalledWith('imgs/a.png', ['/root'], 'ios');
|
||||
expect(value).toBe(mockData.slice(0, 4));
|
||||
done();
|
||||
});
|
||||
|
@ -427,7 +428,7 @@ describe('processRequest', () => {
|
|||
res.end.mockImplementation(value => {
|
||||
expect(getAsset).toBeCalledWith(
|
||||
'imgs/\u{4E3B}\u{9875}/logo.png',
|
||||
['root'],
|
||||
['/root'],
|
||||
undefined,
|
||||
);
|
||||
expect(value).toBe('i am image');
|
||||
|
@ -450,7 +451,7 @@ describe('processRequest', () => {
|
|||
assetPlugins: [],
|
||||
customTransformOptions: {},
|
||||
dev: true,
|
||||
entryFile: 'foo file',
|
||||
entryFile: '/root/foo file',
|
||||
entryModuleOnly: false,
|
||||
excludeSource: false,
|
||||
hot: false,
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`processRequest Generate delta bundle endpoint should send the correct deltaBundlerId to the bundler 1`] = `"{\\"sourceMapUrl\\":null,\\"bundleType\\":\\"delta\\",\\"customTransformOptions\\":{},\\"entryFile\\":\\"index.js\\",\\"deltaBundleId\\":null,\\"dev\\":true,\\"minify\\":false,\\"excludeSource\\":null,\\"hot\\":true,\\"runBeforeMainModule\\":[\\"InitializeCore\\"],\\"runModule\\":true,\\"inlineSourceMap\\":false,\\"isolateModuleIDs\\":false,\\"platform\\":\\"ios\\",\\"resolutionResponse\\":null,\\"entryModuleOnly\\":false,\\"assetPlugins\\":[],\\"onProgress\\":null,\\"unbundle\\":false}"`;
|
||||
exports[`processRequest Generate delta bundle endpoint should send the correct deltaBundlerId to the bundler 1`] = `"{\\"sourceMapUrl\\":null,\\"bundleType\\":\\"delta\\",\\"customTransformOptions\\":{},\\"entryFile\\":\\"/root/index.js\\",\\"deltaBundleId\\":null,\\"dev\\":true,\\"minify\\":false,\\"excludeSource\\":null,\\"hot\\":true,\\"runBeforeMainModule\\":[\\"InitializeCore\\"],\\"runModule\\":true,\\"inlineSourceMap\\":false,\\"isolateModuleIDs\\":false,\\"platform\\":\\"ios\\",\\"resolutionResponse\\":null,\\"entryModuleOnly\\":false,\\"assetPlugins\\":[],\\"onProgress\\":null,\\"unbundle\\":false}"`;
|
||||
|
|
|
@ -17,6 +17,7 @@ const Serializers = require('../DeltaBundler/Serializers/Serializers');
|
|||
const debug = require('debug')('Metro:Server');
|
||||
const defaults = require('../defaults');
|
||||
const formatBundlingError = require('../lib/formatBundlingError');
|
||||
const getAbsolutePath = require('../lib/getAbsolutePath');
|
||||
const getMaxWorkers = require('../lib/getMaxWorkers');
|
||||
const getOrderedDependencyPaths = require('../lib/getOrderedDependencyPaths');
|
||||
const mime = require('mime-types');
|
||||
|
@ -234,6 +235,7 @@ class Server {
|
|||
runBeforeMainModule: this._opts.getModulesRunBeforeMainModule(
|
||||
options.entryFile,
|
||||
),
|
||||
entryFile: getAbsolutePath(options.entryFile, this._opts.projectRoots),
|
||||
};
|
||||
|
||||
const fullBundle = await Serializers.fullBundle(
|
||||
|
@ -255,7 +257,10 @@ class Server {
|
|||
async getRamBundleInfo(options: BundleOptions): Promise<RamBundleInfo> {
|
||||
return await Serializers.getRamBundleInfo(
|
||||
this._deltaBundler,
|
||||
options,
|
||||
{
|
||||
...options,
|
||||
entryFile: getAbsolutePath(options.entryFile, this._opts.projectRoots),
|
||||
},
|
||||
this._opts.getTransformOptions,
|
||||
);
|
||||
}
|
||||
|
@ -263,7 +268,10 @@ class Server {
|
|||
async getAssets(options: BundleOptions): Promise<$ReadOnlyArray<AssetData>> {
|
||||
return await Serializers.getAssets(
|
||||
this._deltaBundler,
|
||||
options,
|
||||
{
|
||||
...options,
|
||||
entryFile: getAbsolutePath(options.entryFile, this._opts.projectRoots),
|
||||
},
|
||||
this._opts.projectRoots,
|
||||
);
|
||||
}
|
||||
|
@ -277,6 +285,7 @@ class Server {
|
|||
const bundleOptions = {
|
||||
...Server.DEFAULT_BUNDLE_OPTIONS,
|
||||
...options,
|
||||
entryFile: getAbsolutePath(options.entryFile, this._opts.projectRoots),
|
||||
bundleType: 'delta',
|
||||
};
|
||||
|
||||
|
@ -813,6 +822,11 @@ class Server {
|
|||
})
|
||||
.join('.') + '.js';
|
||||
|
||||
const absoluteEntryFile = getAbsolutePath(
|
||||
entryFile,
|
||||
this._opts.projectRoots,
|
||||
);
|
||||
|
||||
// try to get the platform from the url
|
||||
const platform =
|
||||
urlQuery.platform ||
|
||||
|
@ -847,7 +861,7 @@ class Server {
|
|||
}),
|
||||
bundleType: isMap ? 'map' : deltaBundleId ? 'delta' : 'bundle',
|
||||
customTransformOptions,
|
||||
entryFile,
|
||||
entryFile: absoluteEntryFile,
|
||||
deltaBundleId,
|
||||
dev,
|
||||
minify,
|
||||
|
@ -891,6 +905,10 @@ class Server {
|
|||
return this._reporter;
|
||||
}
|
||||
|
||||
getProjectRoots(): $ReadOnlyArray<string> {
|
||||
return this._opts.projectRoots;
|
||||
}
|
||||
|
||||
static DEFAULT_BUNDLE_OPTIONS = {
|
||||
assetPlugins: [],
|
||||
customTransformOptions: Object.create(null),
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
|
||||
module.exports = (file: string, roots: $ReadOnlyArray<string>): string =>
|
||||
path.resolve(roots[0], file);
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails oncall+javascript_foundation
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
jest.mock('fs', () => new (require('metro-memory-fs'))());
|
||||
|
||||
const fs = require('fs');
|
||||
const getAbsolutePath = require('../getAbsolutePath');
|
||||
const mkdirp = require('mkdirp');
|
||||
|
||||
beforeEach(() => {
|
||||
fs.reset();
|
||||
|
||||
mkdirp.sync('/root/a');
|
||||
mkdirp.sync('/root/b');
|
||||
mkdirp.sync('/root/a/d');
|
||||
});
|
||||
|
||||
it('should work for a simple case with a single project root', () => {
|
||||
fs.writeFileSync('/root/a/entryPoint.js', '');
|
||||
|
||||
expect(getAbsolutePath('entryPoint.js', ['/root/a'])).toEqual(
|
||||
'/root/a/entryPoint.js',
|
||||
);
|
||||
});
|
||||
|
||||
it('should resolve from the first defined project root', () => {
|
||||
fs.writeFileSync('/root/a/entryPoint.js', '');
|
||||
fs.writeFileSync('/root/b/entryPoint.js', '');
|
||||
|
||||
expect(getAbsolutePath('entryPoint.js', ['/root/a', '/root/c'])).toEqual(
|
||||
'/root/a/entryPoint.js',
|
||||
);
|
||||
});
|
||||
|
||||
it('should resolve from sub-folders', () => {
|
||||
fs.writeFileSync('/root/a/d/entryPoint.js', '');
|
||||
fs.writeFileSync('/root/b/entryPoint.js', '');
|
||||
|
||||
expect(getAbsolutePath('d/entryPoint.js', ['/root/a', '/root/d'])).toEqual(
|
||||
'/root/a/d/entryPoint.js',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an error if not found', () => {
|
||||
expect(() =>
|
||||
getAbsolutePath('entryPoint.js', ['/root/a', '/root/d']),
|
||||
).toThrow();
|
||||
});
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const isAbsolutePath = require('absolute-path');
|
||||
const path = require('path');
|
||||
|
||||
function getAbsolutePath(
|
||||
filePath: string,
|
||||
projectRoots: $ReadOnlyArray<string>,
|
||||
): string {
|
||||
if (isAbsolutePath(filePath)) {
|
||||
return path.resolve(filePath);
|
||||
}
|
||||
|
||||
for (let i = 0; i < projectRoots.length; i++) {
|
||||
const potentialAbsPath = path.resolve(projectRoots[i], filePath);
|
||||
if (fs.existsSync(potentialAbsPath)) {
|
||||
return potentialAbsPath;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundError(filePath, projectRoots);
|
||||
}
|
||||
|
||||
class NotFoundError extends Error {
|
||||
status: number;
|
||||
type: string;
|
||||
|
||||
constructor(relativePath: string, projectRoots: $ReadOnlyArray<string>) {
|
||||
super(
|
||||
`File not found: ${relativePath} in any of the project roots (${projectRoots.join(
|
||||
', ',
|
||||
)})`,
|
||||
);
|
||||
|
||||
this.type = 'NotFoundError';
|
||||
this.status = 404;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = getAbsolutePath;
|
|
@ -19,11 +19,9 @@ const ModuleCache = require('./ModuleCache');
|
|||
const ResolutionRequest = require('./DependencyGraph/ResolutionRequest');
|
||||
|
||||
const fs = require('fs');
|
||||
const isAbsolutePath = require('absolute-path');
|
||||
const parsePlatformFilePath = require('./lib/parsePlatformFilePath');
|
||||
const path = require('path');
|
||||
const toLocalPath = require('../node-haste/lib/toLocalPath');
|
||||
const util = require('util');
|
||||
|
||||
const {ModuleResolver} = require('./DependencyGraph/ModuleResolution');
|
||||
const {EventEmitter} = require('events');
|
||||
|
@ -288,52 +286,9 @@ class DependencyGraph extends EventEmitter {
|
|||
return toLocalPath(this._opts.projectRoots, filePath);
|
||||
}
|
||||
|
||||
getAbsolutePath(filePath: string) {
|
||||
if (isAbsolutePath(filePath)) {
|
||||
return path.resolve(filePath);
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._opts.projectRoots.length; i++) {
|
||||
const root = this._opts.projectRoots[i];
|
||||
const potentialAbsPath = path.join(root, filePath);
|
||||
if (this._hasteFS.exists(potentialAbsPath)) {
|
||||
return path.resolve(potentialAbsPath);
|
||||
}
|
||||
}
|
||||
|
||||
// If we failed to find a file, maybe this is just a Haste name so try that
|
||||
// TODO: We should prefer Haste name resolution first ideally since it is faster
|
||||
// TODO: Ideally, we should not do any `path.parse().name` here and just use the
|
||||
// name, but in `metro/src/Server/index.js` we append `'.js'` to all names
|
||||
// so until that changes, we have to do this.
|
||||
const potentialPath = this._moduleMap.getModule(
|
||||
path.parse(filePath).name,
|
||||
null,
|
||||
);
|
||||
if (potentialPath) {
|
||||
return potentialPath;
|
||||
}
|
||||
|
||||
throw new NotFoundError(
|
||||
'Cannot find entry file %s in any of the roots: %j',
|
||||
filePath,
|
||||
this._opts.projectRoots,
|
||||
);
|
||||
}
|
||||
|
||||
createPolyfill(options: {file: string}) {
|
||||
return this._moduleCache.createPolyfill(options);
|
||||
}
|
||||
}
|
||||
|
||||
function NotFoundError(...args) {
|
||||
Error.call(this);
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
var msg = util.format.apply(util, args);
|
||||
this.message = msg;
|
||||
this.type = this.name = 'NotFoundError';
|
||||
this.status = 404;
|
||||
}
|
||||
util.inherits(NotFoundError, Error);
|
||||
|
||||
module.exports = DependencyGraph;
|
||||
|
|
Loading…
Reference in New Issue