diff --git a/packager/src/Bundler/index.js b/packager/src/Bundler/index.js index a0b1674cc..8619479af 100644 --- a/packager/src/Bundler/index.js +++ b/packager/src/Bundler/index.js @@ -26,13 +26,13 @@ const denodeify = require('denodeify'); const defaults = require('../../defaults'); const os = require('os'); const invariant = require('fbjs/lib/invariant'); +const toLocalPath = require('../node-haste/lib/toLocalPath'); const {generateAssetTransformResult, isAssetTypeAnImage} = require('./util'); const { sep: pathSeparator, join: joinPath, - relative: relativePath, dirname: pathDirname, extname, } = require('path'); @@ -842,19 +842,6 @@ class Bundler { } -function toLocalPath(roots, absPath) { - for (let i = 0; i < roots.length; i++) { - const localPath = relativePath(roots[i], absPath); - if (localPath[0] !== '.') { - return localPath; - } - } - - throw new Error( - 'Expected root module to be relative to one of the project roots' - ); -} - function verifyRootExists(root) { // Verify that the root exists. assert(fs.statSync(root).isDirectory(), 'Root has to be a valid directory'); diff --git a/packager/src/JSTransformer/worker/worker.js b/packager/src/JSTransformer/worker/worker.js index f1890c954..9227e609d 100644 --- a/packager/src/JSTransformer/worker/worker.js +++ b/packager/src/JSTransformer/worker/worker.js @@ -19,6 +19,7 @@ const invariant = require('fbjs/lib/invariant'); const minify = require('./minify'); import type {LogEntry} from '../../Logger/Types'; +import type {LocalPath} from '../../node-haste/lib/toLocalPath'; import type {Ast, Plugins as BabelPlugins, SourceMap as MappingsMap} from 'babel-core'; export type TransformedCode = { diff --git a/packager/src/lib/GlobalTransformCache.js b/packager/src/lib/GlobalTransformCache.js index b7f6145a9..deb27aef9 100644 --- a/packager/src/lib/GlobalTransformCache.js +++ b/packager/src/lib/GlobalTransformCache.js @@ -18,6 +18,7 @@ const FetchError = require('node-fetch/lib/fetch-error'); const crypto = require('crypto'); const fetch = require('node-fetch'); +const invariant = require('fbjs/lib/invariant'); const jsonStableStringify = require('json-stable-stringify'); const path = require('path'); const throat = require('throat'); @@ -26,6 +27,7 @@ import type { Options as TransformWorkerOptions, TransformOptionsStrict, } from '../JSTransformer/worker/worker'; +import type {LocalPath} from '../node-haste/lib/toLocalPath'; import type {CachedResult, GetTransformCacheKey} from './TransformCache'; /** @@ -62,10 +64,10 @@ type FetchResultFromURI = (uri: string) => Promise; type StoreResults = (resultsByKey: Map) => Promise; export type FetchProps = { - filePath: string, - sourceCode: string, - getTransformCacheKey: GetTransformCacheKey, - transformOptions: TransformWorkerOptions, + +localPath: LocalPath, + +sourceCode: string, + +getTransformCacheKey: GetTransformCacheKey, + +transformOptions: TransformWorkerOptions, }; type URI = string; @@ -227,13 +229,13 @@ class URIBasedGlobalTransformCache { */ keyOf(props: FetchProps) { const hash = crypto.createHash('sha1'); - const {sourceCode, filePath, transformOptions} = props; + const {sourceCode, localPath, transformOptions} = props; hash.update(this._optionsHasher.getTransformWorkerOptionsDigest(transformOptions)); const cacheKey = props.getTransformCacheKey(transformOptions); hash.update(JSON.stringify(cacheKey)); hash.update(crypto.createHash('sha1').update(sourceCode).digest('hex')); const digest = hash.digest('hex'); - return `${digest}-${path.basename(filePath)}`; + return `${digest}-${localPath}`; } /** diff --git a/packager/src/lib/TransformCache.js b/packager/src/lib/TransformCache.js index 978405f17..ab1ab19a8 100644 --- a/packager/src/lib/TransformCache.js +++ b/packager/src/lib/TransformCache.js @@ -24,6 +24,7 @@ const writeFileAtomicSync = require('write-file-atomic').sync; import type {Options as WorkerOptions} from '../JSTransformer/worker/worker'; import type {MappingsMap} from './SourceMap'; import type {Reporter} from './reporting'; +import type {LocalPath} from '../node-haste/lib/toLocalPath'; type CacheFilePaths = {transformedCode: string, metadata: string}; export type GetTransformCacheKey = (options: {}) => string; @@ -50,6 +51,7 @@ export type CacheOptions = { export type ReadTransformProps = { filePath: string, + localPath: LocalPath, sourceCode: string, transformOptions: WorkerOptions, transformOptionsKey: string, diff --git a/packager/src/lib/__tests__/GlobalTransformCache-test.js b/packager/src/lib/__tests__/GlobalTransformCache-test.js index 1b1bd7e9f..c95a4e054 100644 --- a/packager/src/lib/__tests__/GlobalTransformCache-test.js +++ b/packager/src/lib/__tests__/GlobalTransformCache-test.js @@ -55,12 +55,12 @@ describe('GlobalTransformCache', () => { }, }; const result = await Promise.all([cache.fetch({ - filePath: 'foo.js', + localPath: 'some/where/foo.js', sourceCode: '/* beep */', getTransformCacheKey: () => 'abcd', transformOptions, }), cache.fetch({ - filePath: 'bar.js', + localPath: 'some/where/else/bar.js', sourceCode: '/* boop */', getTransformCacheKey: () => 'abcd', transformOptions, diff --git a/packager/src/lib/__tests__/__snapshots__/GlobalTransformCache-test.js.snap b/packager/src/lib/__tests__/__snapshots__/GlobalTransformCache-test.js.snap index 8c15dc7cd..9fadc6468 100644 --- a/packager/src/lib/__tests__/__snapshots__/GlobalTransformCache-test.js.snap +++ b/packager/src/lib/__tests__/__snapshots__/GlobalTransformCache-test.js.snap @@ -19,12 +19,12 @@ Object { exports[`GlobalTransformCache fetches results 1`] = ` Array [ Object { - "code": "/* code from http://globalcache.com/cd6df9b7e86839dafc5e9b5b493a28cbc55074e7-foo.js */", + "code": "/* code from http://globalcache.com/cd6df9b7e86839dafc5e9b5b493a28cbc55074e7-some/where/foo.js */", "dependencies": Array [], "dependencyOffsets": Array [], }, Object { - "code": "/* code from http://globalcache.com/6329a317fcf94d74cc9a1de6442ee7c25e27a507-bar.js */", + "code": "/* code from http://globalcache.com/6329a317fcf94d74cc9a1de6442ee7c25e27a507-some/where/else/bar.js */", "dependencies": Array [], "dependencyOffsets": Array [], }, diff --git a/packager/src/node-haste/DependencyGraph.js b/packager/src/node-haste/DependencyGraph.js index b950f2b1a..89e052187 100644 --- a/packager/src/node-haste/DependencyGraph.js +++ b/packager/src/node-haste/DependencyGraph.js @@ -162,14 +162,15 @@ class DependencyGraph extends EventEmitter { _createModuleCache() { const {_opts} = this; return new ModuleCache({ + assetDependencies: _opts.assetDependencies, + depGraphHelpers: this._helpers, + getClosestPackage: this._getClosestPackage.bind(this), getTransformCacheKey: _opts.getTransformCacheKey, globalTransformCache: _opts.globalTransformCache, - transformCode: _opts.transformCode, - depGraphHelpers: this._helpers, - assetDependencies: _opts.assetDependencies, moduleOptions: _opts.moduleOptions, reporter: _opts.reporter, - getClosestPackage: this._getClosestPackage.bind(this), + roots: _opts.roots, + transformCode: _opts.transformCode, }, _opts.platforms); } diff --git a/packager/src/node-haste/Module.js b/packager/src/node-haste/Module.js index 10b8b9aa9..c406e80f8 100644 --- a/packager/src/node-haste/Module.js +++ b/packager/src/node-haste/Module.js @@ -35,6 +35,7 @@ import type {Reporter} from '../lib/reporting'; import type DependencyGraphHelpers from './DependencyGraph/DependencyGraphHelpers'; import type ModuleCache from './ModuleCache'; +import type {LocalPath} from './lib/toLocalPath'; export type ReadResult = { +code: string, @@ -74,6 +75,7 @@ export type ConstructorArgs = { depGraphHelpers: DependencyGraphHelpers, globalTransformCache: ?GlobalTransformCache, file: string, + localPath: LocalPath, moduleCache: ModuleCache, options: Options, reporter: Reporter, @@ -86,6 +88,7 @@ type DocBlock = {+[key: string]: string}; const TRANSFORM_CACHE = new TransformCache(); class Module { + localPath: LocalPath; path: string; type: string; @@ -106,6 +109,7 @@ class Module { constructor({ depGraphHelpers, + localPath, file, getTransformCacheKey, globalTransformCache, @@ -118,6 +122,7 @@ class Module { throw new Error('Expected file to be absolute path but got ' + file); } + this.localPath = localPath; this.path = file; this.type = 'Module'; @@ -436,6 +441,7 @@ class Module { const getTransformCacheKey = this._getTransformCacheKey; return { filePath: this.path, + localPath: this.localPath, sourceCode, getTransformCacheKey, transformOptions, diff --git a/packager/src/node-haste/ModuleCache.js b/packager/src/node-haste/ModuleCache.js index 0a183b161..c1f0a2d34 100644 --- a/packager/src/node-haste/ModuleCache.js +++ b/packager/src/node-haste/ModuleCache.js @@ -17,6 +17,8 @@ const Module = require('./Module'); const Package = require('./Package'); const Polyfill = require('./Polyfill'); +const toLocalPath = require('./lib/toLocalPath'); + import type {GlobalTransformCache} from '../lib/GlobalTransformCache'; import type {GetTransformCacheKey} from '../lib/TransformCache'; import type {Reporter} from '../lib/reporting'; @@ -39,6 +41,7 @@ class ModuleCache { _platforms: Set; _transformCode: TransformCode; _reporter: Reporter; + _roots: Array; constructor( { @@ -49,18 +52,20 @@ class ModuleCache { getTransformCacheKey, globalTransformCache, moduleOptions, + roots, reporter, transformCode, - }: { + }: {| assetDependencies: Array, depGraphHelpers: DependencyGraphHelpers, getClosestPackage: GetClosestPackageFn, getTransformCacheKey: GetTransformCacheKey, globalTransformCache: ?GlobalTransformCache, moduleOptions: ModuleOptions, + roots: Array, reporter: Reporter, transformCode: TransformCode, - }, + |}, platforms: Set, ) { this._assetDependencies = assetDependencies; @@ -75,6 +80,7 @@ class ModuleCache { this._platforms = platforms; this._transformCode = transformCode; this._reporter = reporter; + this._roots = roots; } getModule(filePath: string): Module { @@ -84,6 +90,7 @@ class ModuleCache { file: filePath, getTransformCacheKey: this._getTransformCacheKey, globalTransformCache: this._globalTransformCache, + localPath: toLocalPath(this._roots, filePath), moduleCache: this, options: this._moduleOptions, reporter: this._reporter, @@ -99,14 +106,22 @@ class ModuleCache { getAssetModule(filePath: string) { if (!this._moduleCache[filePath]) { - /* $FlowFixMe: missing options. This is because this is an incorrect OOP - * design in the first place: AssetModule, being simpler than a normal - * Module, should not inherit the Module class. */ + /* FixMe: AssetModule does not need all these options. This is because + * this is an incorrect OOP design in the first place: AssetModule, being + * simpler than a normal Module, should not inherit the Module class. + */ this._moduleCache[filePath] = new AssetModule( { - file: filePath, - moduleCache: this, dependencies: this._assetDependencies, + depGraphHelpers: this._depGraphHelpers, + file: filePath, + getTransformCacheKey: this._getTransformCacheKey, + globalTransformCache: null, + localPath: toLocalPath(this._roots, filePath), + moduleCache: this, + options: this._moduleOptions, + reporter: this._reporter, + transformCode: this._transformCode, }, this._platforms, ); @@ -149,6 +164,7 @@ class ModuleCache { file, depGraphHelpers: this._depGraphHelpers, getTransformCacheKey: this._getTransformCacheKey, + localPath: toLocalPath(this._roots, file), moduleCache: this, transformCode: this._transformCode, }); diff --git a/packager/src/node-haste/lib/toLocalPath.js b/packager/src/node-haste/lib/toLocalPath.js new file mode 100644 index 000000000..dbdb2037e --- /dev/null +++ b/packager/src/node-haste/lib/toLocalPath.js @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @flow + */ + +'use strict'; + +const {relative} = require('path'); + +declare class OpaqueLocalPath {} +export type LocalPath = OpaqueLocalPath & string; + +// FIXME: This function has the shortcoming of potentially returning identical +// paths for two files in different roots. +function toLocalPath(roots: Array, absolutePath: string): LocalPath { + for (let i = 0; i < roots.length; i++) { + const localPath = relative(roots[i], absolutePath); + if (localPath[0] !== '.') { + return (localPath: any); + } + } + + throw new Error( + 'Expected root module to be relative to one of the project roots' + ); +} + +module.exports = toLocalPath;