Skip to content

Commit

Permalink
fix #2754: plugins can now resolve injected files
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Dec 16, 2022
1 parent e2ae29b commit 6988145
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 213 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,10 @@

## Unreleased

* Allow plugins to resolve injected files ([#2754](https://github.com/evanw/esbuild/issues/2754))

Previously paths passed to the `inject` feature were always interpreted as file system paths. This meant that `onResolve` plugins would not be run for them and esbuild's default path resolver would always be used. This meant that the `inject` feature couldn't be used in the browser since the browser doesn't have access to a file system. This release runs paths passed to `inject` through esbuild's full path resolution pipeline so plugins now have a chance to handle them using `onResolve` callbacks. This makes it possible to write a plugin that makes esbuild's `inject` work in the browser.

* Add the `empty` loader ([#1541](https://github.com/evanw/esbuild/issues/1541), [#2753](https://github.com/evanw/esbuild/issues/2753))

The new `empty` loader tells esbuild to pretend that a file is empty. So for example `--loader:.css=empty` effectively skips all imports of `.css` files in JavaScript so that they aren't included in the bundle, since `import "./some-empty-file"` in JavaScript doesn't bundle anything. You can also use the `empty` loader to remove asset references in CSS files. For example `--loader:.png=empty` causes esbuild to replace asset references such as `url(image.png)` with `url()` so that they are no longer included in the resulting style sheet.
Expand Down
429 changes: 242 additions & 187 deletions internal/bundler/bundler.go

Large diffs are not rendered by default.

37 changes: 18 additions & 19 deletions internal/bundler_tests/bundler_default_test.go
Expand Up @@ -2919,11 +2919,11 @@ func TestUseStrictDirectiveBundleIssue1837(t *testing.T) {
},
entryPaths: []string{"/entry.js"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
InjectAbsPaths: []string{"/shims.js"},
Platform: config.PlatformNode,
OutputFormat: config.FormatIIFE,
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
InjectPaths: []string{"/shims.js"},
Platform: config.PlatformNode,
OutputFormat: config.FormatIIFE,
},
})
}
Expand Down Expand Up @@ -4127,11 +4127,11 @@ func TestInjectMissing(t *testing.T) {
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject.js",
},
},
expectedScanLog: "ERROR: Could not read from file: /inject.js\n",
expectedScanLog: "ERROR: Could not resolve \"/inject.js\"\n",
})

default_suite.expectBundledWindows(t, bundled{
Expand All @@ -4142,31 +4142,30 @@ func TestInjectMissing(t *testing.T) {
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject.js",
},
},
expectedScanLog: "ERROR: Could not read from file: C:\\inject.js\n",
expectedScanLog: "ERROR: Could not resolve \"C:\\\\inject.js\"\n",
})
}

// Duplicates are allowed, and should only be injected once
func TestInjectDuplicate(t *testing.T) {
default_suite.expectBundled(t, bundled{
files: map[string]string{
"/entry.js": ``,
"/inject.js": ``,
"/inject.js": `console.log('injected')`,
},
entryPaths: []string{"/entry.js"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject.js",
"/inject.js",
},
},
expectedScanLog: `ERROR: Duplicate injected file "inject.js"
`,
})
}

Expand Down Expand Up @@ -4233,7 +4232,7 @@ func TestInject(t *testing.T) {
AbsOutputFile: "/out.js",
Defines: &defines,
OutputFormat: config.FormatCommonJS,
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject.js",
"/node_modules/unused/index.js",
"/node_modules/sideEffects-false/index.js",
Expand Down Expand Up @@ -4313,7 +4312,7 @@ func TestInjectNoBundle(t *testing.T) {
TreeShaking: true,
AbsOutputFile: "/out.js",
Defines: &defines,
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject.js",
"/node_modules/unused/index.js",
"/node_modules/sideEffects-false/index.js",
Expand Down Expand Up @@ -4353,7 +4352,7 @@ func TestInjectJSX(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
Defines: &defines,
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject.js",
},
},
Expand All @@ -4380,7 +4379,7 @@ func TestInjectImportTS(t *testing.T) {
Mode: config.ModeConvertFormat,
OutputFormat: config.FormatESModule,
AbsOutputFile: "/out.js",
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject.js",
},
},
Expand All @@ -4407,7 +4406,7 @@ func TestInjectImportOrder(t *testing.T) {
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject-1.js",
"/inject-2.js",
},
Expand Down Expand Up @@ -4436,7 +4435,7 @@ func TestInjectAssign(t *testing.T) {
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
InjectAbsPaths: []string{
InjectPaths: []string{
"/inject.js",
},
},
Expand Down
4 changes: 2 additions & 2 deletions internal/bundler_tests/bundler_test.go
Expand Up @@ -130,8 +130,8 @@ func (s *suite) __expectBundledImpl(t *testing.T, args bundled, fsKind fs.MockKi
entryPoints[i] = entry
}

for i, absPath := range args.options.InjectAbsPaths {
args.options.InjectAbsPaths[i] = unix2win(absPath)
for i, absPath := range args.options.InjectPaths {
args.options.InjectPaths[i] = unix2win(absPath)
}

for key, value := range args.options.PackageAliases {
Expand Down
6 changes: 6 additions & 0 deletions internal/bundler_tests/snapshots/snapshots_default.txt
Expand Up @@ -1477,6 +1477,12 @@ console.log(replace.test);
console.log(collide);
console.log(import_external_pkg.re_export);

================================================================================
TestInjectDuplicate
---------- /out.js ----------
// inject.js
console.log("injected");

================================================================================
TestInjectImportOrder
---------- /out.js ----------
Expand Down
2 changes: 1 addition & 1 deletion internal/config/config.go
Expand Up @@ -286,7 +286,7 @@ type Options struct {
ExtensionToLoader map[string]Loader

PublicPath string
InjectAbsPaths []string
InjectPaths []string
InjectedDefines []InjectedDefine
InjectedFiles []InjectedFile

Expand Down
5 changes: 1 addition & 4 deletions pkg/api/api_impl.go
Expand Up @@ -1011,7 +1011,7 @@ func rebuildImpl(
MainFields: buildOpts.MainFields,
PublicPath: buildOpts.PublicPath,
KeepNames: buildOpts.KeepNames,
InjectAbsPaths: make([]string, len(buildOpts.Inject)),
InjectPaths: append([]string{}, buildOpts.Inject...),
AbsNodePaths: make([]string, len(buildOpts.NodePaths)),
JSBanner: bannerJS,
JSFooter: footerJS,
Expand All @@ -1027,9 +1027,6 @@ func rebuildImpl(
if options.MainFields != nil {
options.MainFields = append([]string{}, options.MainFields...)
}
for i, path := range buildOpts.Inject {
options.InjectAbsPaths[i] = validatePath(log, realFS, path, "inject path")
}
for i, path := range buildOpts.NodePaths {
options.AbsNodePaths[i] = validatePath(log, realFS, path, "node path")
}
Expand Down
22 changes: 22 additions & 0 deletions scripts/plugin-tests.js
Expand Up @@ -2367,6 +2367,28 @@ error: Invalid path suffix "%what" returned from plugin (must start with "?" or
})
assert.strictEqual(result.outputFiles[0].text, `console.log(123);\n`)
},

async injectWithVirtualFile({ esbuild, testDir }) {
const input = path.join(testDir, 'input.js')
await writeFileAsync(input, `console.log(test)`)
const result = await esbuild.build({
entryPoints: [input],
write: false,
inject: ['plugin-file'],
plugins: [{
name: 'plugin',
setup(build) {
build.onResolve({ filter: /^plugin-file$/ }, () => {
return { namespace: 'plugin', path: 'path' }
})
build.onLoad({ filter: /^path$/, namespace: 'plugin' }, () => {
return { contents: `export let test = 'injected'` }
})
},
}],
})
assert.strictEqual(result.outputFiles[0].text, `var test = "injected";\nconsole.log(test);\n`)
},
}

// These tests have to run synchronously
Expand Down

0 comments on commit 6988145

Please sign in to comment.