Skip to content

Use file hash to check for file changes before transpiling (#299) #313

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

Merged
merged 5 commits into from
Sep 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = crlf
indent_size = 4
indent_style = tab
insert_final_newline = true

[*.json]
indent_size = 2
indent_style = space
29 changes: 27 additions & 2 deletions src/React.Core/Babel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -350,12 +350,37 @@ string filename
)
{
var outputPath = GetOutputPath(filename);
var sourceMapPath = GetSourceMapOutputPath(filename);
var contents = _fileSystem.ReadAsString(filename);
if (CacheIsValid(contents, outputPath))
return outputPath;

var result = TransformWithHeader(filename, contents, null);

var sourceMapPath = GetSourceMapOutputPath(filename);
_fileSystem.WriteAsString(outputPath, result.Code);
_fileSystem.WriteAsString(sourceMapPath, result.SourceMap == null ? string.Empty : result.SourceMap.ToJson());
_fileSystem.WriteAsString(sourceMapPath, result.SourceMap == null ? string.Empty : result.SourceMap.ToJson());

return outputPath;
}

/// <summary>
/// Checks whether an input file (given as inputFileContents) should be transpiled
/// by calculating the hash and comparing it to the hash value stored
/// in the file given by outputPath. If the outputPath file does not
/// exist the input file should always be transpiled.
/// </summary>
/// <param name="inputFileContents">The contents of the input file.</param>
/// <param name="outputPath">The output path of the (possibly previously) generated file.</param>
/// <returns>Returns false if the file should be transpiled, true otherwise.</returns>
public virtual bool CacheIsValid(string inputFileContents, string outputPath)
{
if (!_fileSystem.FileExists(outputPath))
return false;

var hashForInputFile = _fileCacheHash.CalculateHash(inputFileContents);
var existingOutputContents = _fileSystem.ReadAsString(outputPath);
var fileHasNotChanged = _fileCacheHash.ValidateHash(existingOutputContents, hashForInputFile);
return fileHasNotChanged;
}
}
}
27 changes: 27 additions & 0 deletions src/React.Tests/Core/BabelTransformerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public void SetUp()
_fileSystem = new Mock<IFileSystem>();
_fileSystem.Setup(x => x.MapPath(It.IsAny<string>())).Returns<string>(x => x);

// Per default the output file should not exist, then individual tests
// can choose otherwise.
_fileSystem.Setup(x => x.FileExists(It.IsAny<string>())).Returns(false);

_fileCacheHash = new Mock<IFileCacheHash>();

_babel = new Babel(
Expand Down Expand Up @@ -152,6 +156,29 @@ public void ShouldSaveTransformationResult()
StringAssert.EndsWith("React.DOM.div('Hello World')", result);
}

[Test]
public void ShouldSkipTransformationIfCacheIsValid()
{
_fileSystem.Setup(x => x.ReadAsString("foo.jsx")).Returns("<div>Hello World</div>");
_fileSystem.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true);
_fileCacheHash.Setup(x => x.ValidateHash(It.IsAny<string>(), It.IsAny<string>())).Returns(true);
_environment.Setup(x => x.ExecuteWithBabel<JavaScriptWithSourceMap>(
"ReactNET_transform_sourcemap",
It.IsAny<string>(),
It.IsAny<string>(), // Babel config
"foo.jsx" // File name
)).Returns(new JavaScriptWithSourceMap { Code = "React.DOM.div('Hello World')" });

string result = null;
_fileSystem.Setup(x => x.WriteAsString("foo.generated.js", It.IsAny<string>())).Callback(
(string filename, string contents) => result = contents
);

var resultFilename = _babel.TransformAndSaveFile("foo.jsx");
Assert.AreEqual("foo.generated.js", resultFilename);
Assert.IsNull(result, "There should be no result. Cached result should have been used.");
}

private void SetUpEmptyCache()
{
_cache.Setup(x => x.Get<JavaScriptWithSourceMap>("JSX_v3_foo.jsx", null)).Returns((JavaScriptWithSourceMap)null);
Expand Down