mirror of
https://github.com/zhigang1992/esbuild.git
synced 2026-05-28 08:18:01 +08:00
don't use contents for file loader hash
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"mime"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/evanw/esbuild/internal/ast"
|
||||
@@ -184,17 +185,10 @@ func parseFile(args parseArgs) {
|
||||
result.file.ignoreIfUnused = true
|
||||
|
||||
case LoaderFile:
|
||||
// Get the file name, making sure to use the "fs" interface so we do the
|
||||
// right thing on Windows (Windows-style paths for the command-line
|
||||
// interface and Unix-style paths for tests, even on Windows)
|
||||
baseName := args.fs.Base(args.absPath)
|
||||
|
||||
// Add a hash to the file name to prevent multiple files with the same name
|
||||
// but different contents from colliding
|
||||
bytes := []byte(source.Contents)
|
||||
hashBytes := sha1.Sum(bytes)
|
||||
hash := base64.URLEncoding.EncodeToString(hashBytes[:])[:8]
|
||||
baseName = baseName[:len(baseName)-len(extension)] + "." + hash + extension
|
||||
// Add a hash to the file name to prevent multiple files with the same base
|
||||
// name from colliding. Avoid using the absolute path to prevent build
|
||||
// output from being different on different machines.
|
||||
baseName := baseNameForAvoidingCollisions(args.fs, args.absPath)
|
||||
|
||||
// Determine the destination folder
|
||||
targetFolder := args.bundleOptions.AbsOutputDir
|
||||
@@ -218,7 +212,7 @@ func parseFile(args parseArgs) {
|
||||
// the file if the module isn't removed due to tree shaking.
|
||||
result.file.additionalFile = &OutputFile{
|
||||
AbsPath: args.fs.Join(targetFolder, baseName),
|
||||
Contents: bytes,
|
||||
Contents: []byte(source.Contents),
|
||||
jsonMetadataChunk: jsonMetadataChunk,
|
||||
}
|
||||
|
||||
@@ -231,6 +225,30 @@ func parseFile(args parseArgs) {
|
||||
args.results <- result
|
||||
}
|
||||
|
||||
func baseNameForAvoidingCollisions(fs fs.FS, absPath string) string {
|
||||
var toHash []byte
|
||||
if relPath, ok := fs.RelativeToCwd(absPath); ok {
|
||||
// Attempt to generate the same base name regardless of what machine or
|
||||
// operating system we're on. We want to avoid absolute paths because they
|
||||
// will have different home directories. We also want to avoid path
|
||||
// separators because they are different on Windows.
|
||||
toHash = []byte(strings.ReplaceAll(relPath, "\\", "/"))
|
||||
} else {
|
||||
// Just use the absolute path if this environment doesn't have a current
|
||||
// directory. This is the case when running tests, for example.
|
||||
toHash = []byte(absPath)
|
||||
}
|
||||
|
||||
// Use "URLEncoding" instead of "StdEncoding" to avoid introducing "/"
|
||||
hashBytes := sha1.Sum(toHash)
|
||||
hash := base64.URLEncoding.EncodeToString(hashBytes[:])[:8]
|
||||
|
||||
// Insert the hash before the extension
|
||||
base := fs.Base(absPath)
|
||||
ext := fs.Ext(absPath)
|
||||
return base[:len(base)-len(ext)] + "." + hash + ext
|
||||
}
|
||||
|
||||
func ScanBundle(
|
||||
log logging.Log, fs fs.FS, res resolver.Resolver, entryPaths []string,
|
||||
parseOptions parser.ParseOptions, bundleOptions BundleOptions,
|
||||
|
||||
@@ -2807,11 +2807,12 @@ func TestLoaderFile(t *testing.T) {
|
||||
expectBundled(t, bundled{
|
||||
files: map[string]string{
|
||||
"/entry.js": `
|
||||
console.log(require('./test.svg'))
|
||||
console.log(require('./test3.svg'))
|
||||
`,
|
||||
|
||||
// Use an SVG string that has a base64-encoded SHA1 has with a "/" in it
|
||||
"/test.svg": "<svg>$</svg>",
|
||||
// "/test3.svg" generates the file name "test3.0sKdZN/F.svg" if the
|
||||
// standard base64 encoding is used instead of the URL base64 encoding
|
||||
"/test3.svg": "<svg></svg>",
|
||||
},
|
||||
entryPaths: []string{"/entry.js"},
|
||||
parseOptions: parser.ParseOptions{
|
||||
@@ -2826,14 +2827,60 @@ func TestLoaderFile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expected: map[string]string{
|
||||
"/out/test.1HOBn_hi.svg": "<svg>$</svg>",
|
||||
"/out/entry.js": `// /test.svg
|
||||
var require_test = __commonJS((exports, module) => {
|
||||
module.exports = "test.1HOBn_hi.svg";
|
||||
"/out/test3.0sKdZN_F.svg": "<svg></svg>",
|
||||
"/out/entry.js": `// /test3.svg
|
||||
var require_test3 = __commonJS((exports, module) => {
|
||||
module.exports = "test3.0sKdZN_F.svg";
|
||||
});
|
||||
|
||||
// /entry.js
|
||||
console.log(require_test());
|
||||
console.log(require_test3());
|
||||
`,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoaderFileMultipleNoCollision(t *testing.T) {
|
||||
expectBundled(t, bundled{
|
||||
files: map[string]string{
|
||||
"/entry.js": `
|
||||
console.log(
|
||||
require('./a/test.txt'),
|
||||
require('./b/test.txt'),
|
||||
)
|
||||
`,
|
||||
|
||||
// Two files with the same contents but different paths
|
||||
"/a/test.txt": "test",
|
||||
"/b/test.txt": "test",
|
||||
},
|
||||
entryPaths: []string{"/entry.js"},
|
||||
parseOptions: parser.ParseOptions{
|
||||
IsBundling: true,
|
||||
},
|
||||
bundleOptions: BundleOptions{
|
||||
IsBundling: true,
|
||||
AbsOutputFile: "/dist/out.js",
|
||||
ExtensionToLoader: map[string]Loader{
|
||||
".js": LoaderJS,
|
||||
".txt": LoaderFile,
|
||||
},
|
||||
},
|
||||
expected: map[string]string{
|
||||
"/dist/test.d-VvEp_S.txt": "test",
|
||||
"/dist/test.pL3kpHJC.txt": "test",
|
||||
"/dist/out.js": `// /a/test.txt
|
||||
var require_test = __commonJS((exports, module) => {
|
||||
module.exports = "test.d-VvEp_S.txt";
|
||||
});
|
||||
|
||||
// /b/test.txt
|
||||
var require_test2 = __commonJS((exports, module) => {
|
||||
module.exports = "test.pL3kpHJC.txt";
|
||||
});
|
||||
|
||||
// /entry.js
|
||||
console.log(require_test(), require_test2());
|
||||
`,
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user