Use local paths for global cache

Summary:
Changes the global cache to use *local paths* rather than base names of files for the cache key. This is to enable correct usage of babel transforms like `transform-react-jsx-source` that use file paths in their output.

It remains a responsibility of the transform implementer to pass relative paths to babel if the global cache is being used.

Reviewed By: jeanlauliac

Differential Revision: D5044028

fbshipit-source-id: 2ef1e1545e510a18ab49a307053d91b4f40269b2
This commit is contained in:
David Aurelio 2017-05-11 16:37:06 -07:00 коммит произвёл Facebook Github Bot
Родитель ee8e721c33
Коммит 143beaf95d
10 изменённых файлов: 84 добавлений и 35 удалений

Просмотреть файл

@ -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');

Просмотреть файл

@ -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 = {

Просмотреть файл

@ -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<?CachedResult>;
type StoreResults = (resultsByKey: Map<string, CachedResult>) => Promise<void>;
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}`;
}
/**

Просмотреть файл

@ -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,

Просмотреть файл

@ -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,

Просмотреть файл

@ -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 [],
},

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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,

Просмотреть файл

@ -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<string>;
_transformCode: TransformCode;
_reporter: Reporter;
_roots: Array<string>;
constructor(
{
@ -49,18 +52,20 @@ class ModuleCache {
getTransformCacheKey,
globalTransformCache,
moduleOptions,
roots,
reporter,
transformCode,
}: {
}: {|
assetDependencies: Array<string>,
depGraphHelpers: DependencyGraphHelpers,
getClosestPackage: GetClosestPackageFn,
getTransformCacheKey: GetTransformCacheKey,
globalTransformCache: ?GlobalTransformCache,
moduleOptions: ModuleOptions,
roots: Array<string>,
reporter: Reporter,
transformCode: TransformCode,
},
|},
platforms: Set<string>,
) {
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,
});

Просмотреть файл

@ -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<string>, 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;