Skip to content

Commit

Permalink
import-is-undefined now defaults to warning
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jul 18, 2023
1 parent af0fe32 commit 220141e
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 22 deletions.
56 changes: 54 additions & 2 deletions internal/bundler_tests/bundler_css_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,7 @@ func TestCSSFromJSMissingStarImport(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputDir: "/out",
},
debugLogs: true,
expectedCompileLog: `entry.js: DEBUG: Import "missing" will always be undefined because there is no matching export in "a.css"
expectedCompileLog: `entry.js: WARNING: Import "missing" will always be undefined because there is no matching export in "a.css"
`,
})
}
Expand Down Expand Up @@ -194,6 +193,9 @@ func TestImportGlobalCSSFromJS(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputDir: "/out",
},
expectedCompileLog: `a.js: WARNING: Import "a" will always be undefined because there is no matching export in "a.css"
b.js: WARNING: Import "b" will always be undefined because there is no matching export in "b.css"
`,
})
}

Expand Down Expand Up @@ -1122,3 +1124,53 @@ func TestDeduplicateRules(t *testing.T) {
},
})
}

// This test makes sure JS files that import local CSS names using the
// wrong name (e.g. a typo) get a warning so that the problem is noticed.
func TestUndefinedImportWarningCSS(t *testing.T) {
css_suite.expectBundled(t, bundled{
files: map[string]string{
"/entry.js": `
import * as empty_js from './empty.js'
import * as empty_esm_js from './empty.esm.js'
import * as empty_json from './empty.json'
import * as empty_css from './empty.css'
import * as empty_global_css from './empty.global-css'
import * as empty_local_css from './empty.local-css'
console.log(
empty_js.foo,
empty_esm_js.foo,
empty_json.foo,
empty_css.foo,
empty_global_css.foo,
empty_local_css.foo,
)
`,
"/empty.js": ``,
"/empty.esm.js": `export {}`,
"/empty.json": `{}`,
"/empty.css": ``,
"/empty.global-css": ``,
"/empty.local-css": ``,
},
entryPaths: []string{"/entry.js"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputDir: "/out",
ExtensionToLoader: map[string]config.Loader{
".js": config.LoaderJS,
".json": config.LoaderJSON,
".css": config.LoaderCSS,
".global-css": config.LoaderGlobalCSS,
".local-css": config.LoaderLocalCSS,
},
},
expectedCompileLog: `entry.js: WARNING: Import "foo" will always be undefined because the file "empty.js" has no exports
entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "empty.esm.js"
entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "empty.json"
entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "empty.css"
entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "empty.global-css"
entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "empty.local-css"
`,
})
}
30 changes: 11 additions & 19 deletions internal/bundler_tests/bundler_importstar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1065,8 +1065,7 @@ func TestNamespaceImportMissingES6(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
},
debugLogs: true,
expectedCompileLog: `entry.js: DEBUG: Import "foo" will always be undefined because there is no matching export in "foo.js"
expectedCompileLog: `entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "foo.js"
`,
})
}
Expand Down Expand Up @@ -1128,8 +1127,7 @@ func TestNamespaceImportUnusedMissingES6(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
},
debugLogs: true,
expectedCompileLog: `entry.js: DEBUG: Import "foo" will always be undefined because there is no matching export in "foo.js"
expectedCompileLog: `entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "foo.js"
`,
})
}
Expand Down Expand Up @@ -1285,8 +1283,7 @@ func TestNamespaceImportReExportStarMissingES6(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
},
debugLogs: true,
expectedCompileLog: `entry.js: DEBUG: Import "foo" will always be undefined because there is no matching export in "foo.js"
expectedCompileLog: `entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "foo.js"
`,
})
}
Expand All @@ -1310,8 +1307,7 @@ func TestNamespaceImportReExportStarUnusedMissingES6(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
},
debugLogs: true,
expectedCompileLog: `entry.js: DEBUG: Import "foo" will always be undefined because there is no matching export in "foo.js"
expectedCompileLog: `entry.js: WARNING: Import "foo" will always be undefined because there is no matching export in "foo.js"
`,
})
}
Expand Down Expand Up @@ -1665,9 +1661,8 @@ func TestImportDefaultNamespaceComboIssue446(t *testing.T) {
}},
},
},
debugLogs: true,
expectedCompileLog: `internal-def.js: DEBUG: Import "def" will always be undefined because there is no matching export in "internal.js"
internal-ns-def.js: DEBUG: Import "def" will always be undefined because there is no matching export in "internal.js"
expectedCompileLog: `internal-def.js: WARNING: Import "def" will always be undefined because there is no matching export in "internal.js"
internal-ns-def.js: WARNING: Import "def" will always be undefined because there is no matching export in "internal.js"
`,
})
}
Expand All @@ -1693,14 +1688,13 @@ func TestImportDefaultNamespaceComboNoDefault(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputDir: "/out",
},
debugLogs: true,
expectedCompileLog: `entry-default-ns-prop.js: ERROR: No matching export in "foo.js" for import "default"
entry-default-ns-prop.js: DEBUG: Import "default" will always be undefined because there is no matching export in "foo.js"
entry-default-ns-prop.js: WARNING: Import "default" will always be undefined because there is no matching export in "foo.js"
entry-default-ns.js: ERROR: No matching export in "foo.js" for import "default"
entry-default-prop.js: ERROR: No matching export in "foo.js" for import "default"
entry-default-prop.js: DEBUG: Import "default" will always be undefined because there is no matching export in "foo.js"
entry-default-prop.js: WARNING: Import "default" will always be undefined because there is no matching export in "foo.js"
entry-default.js: ERROR: No matching export in "foo.js" for import "default"
entry-prop.js: DEBUG: Import "default" will always be undefined because there is no matching export in "foo.js"
entry-prop.js: WARNING: Import "default" will always be undefined because there is no matching export in "foo.js"
`,
})
}
Expand Down Expand Up @@ -1746,8 +1740,7 @@ func TestImportNamespaceUndefinedPropertyEmptyFile(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputDir: "/out",
},
debugLogs: true,
expectedCompileLog: `entry-default.js: DEBUG: Import "default" will always be undefined because there is no matching export in "empty.mjs"
expectedCompileLog: `entry-default.js: WARNING: Import "default" will always be undefined because there is no matching export in "empty.mjs"
entry-nope.js: WARNING: Import "nope" will always be undefined because the file "empty.js" has no exports
entry-nope.js: WARNING: Import "nope" will always be undefined because the file "empty.mjs" has no exports
entry-nope.js: WARNING: Import "nope" will always be undefined because the file "empty.cjs" has no exports
Expand Down Expand Up @@ -1797,8 +1790,7 @@ func TestImportNamespaceUndefinedPropertySideEffectFreeFile(t *testing.T) {
Mode: config.ModeBundle,
AbsOutputDir: "/out",
},
debugLogs: true,
expectedCompileLog: `entry-default.js: DEBUG: Import "default" will always be undefined because there is no matching export in "foo/no-side-effects.mjs"
expectedCompileLog: `entry-default.js: WARNING: Import "default" will always be undefined because there is no matching export in "foo/no-side-effects.mjs"
entry-nope.js: WARNING: Import "nope" will always be undefined because the file "foo/no-side-effects.js" has no exports
entry-nope.js: WARNING: Import "nope" will always be undefined because the file "foo/no-side-effects.mjs" has no exports
entry-nope.js: WARNING: Import "nope" will always be undefined because the file "foo/no-side-effects.cjs" has no exports
Expand Down
25 changes: 25 additions & 0 deletions internal/bundler_tests/snapshots/snapshots_css.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1240,3 +1240,28 @@ TestTextImportURLInCSSText
a {
background: url(data:text/plain;base64,VGhpcyBpcyBzb21lIHRleHQu);
}

================================================================================
TestUndefinedImportWarningCSS
---------- /out/entry.js ----------
// empty.js
var require_empty = __commonJS({
"empty.js"() {
}
});

// entry.js
var empty_js = __toESM(require_empty());
console.log(
void 0,
void 0,
void 0,
void 0,
void 0,
void 0
);

---------- /out/entry.css ----------
/* empty.css */
/* empty.global-css */
/* empty.local-css */
2 changes: 1 addition & 1 deletion internal/linker/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2510,7 +2510,7 @@ loop:
// time, so we emit a debug message and rewrite the value to the literal
// "undefined" instead of emitting an error.
symbol.ImportItemStatus = ast.ImportItemMissing
c.log.AddID(logger.MsgID_Bundler_ImportIsUndefined, logger.Debug, trackerFile.LineColumnTracker(), r, fmt.Sprintf(
c.log.AddID(logger.MsgID_Bundler_ImportIsUndefined, logger.Warning, trackerFile.LineColumnTracker(), r, fmt.Sprintf(
"Import %q will always be undefined because there is no matching export in %q",
namedImport.Alias, c.graph.Files[nextTracker.sourceIndex].InputFile.Source.PrettyPath))
} else {
Expand Down
24 changes: 24 additions & 0 deletions scripts/end-to-end-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2229,13 +2229,29 @@ tests.push(
if (ns.default !== void 0) throw 'fail'
`,
'node_modules/pkg/index.mjs': ``,
}, {
expectedStderr: `▲ [WARNING] Import "default" will always be undefined because there is no matching export in "node_modules/pkg/index.mjs" [import-is-undefined]
in.js:3:13:
3 │ if (ns.default !== void 0) throw 'fail'
╵ ~~~~~~~
`,
}),
test(['in.js', '--outfile=node.js', '--bundle'], {
'in.js': `
import * as ns from 'pkg/index.mts'
if (ns.default !== void 0) throw 'fail'
`,
'node_modules/pkg/index.mts': ``,
}, {
expectedStderr: `▲ [WARNING] Import "default" will always be undefined because there is no matching export in "node_modules/pkg/index.mts" [import-is-undefined]
in.js:3:13:
3 │ if (ns.default !== void 0) throw 'fail'
╵ ~~~~~~~
`,
}),
test(['in.js', '--outfile=node.js', '--bundle'], {
'in.js': `
Expand All @@ -2256,6 +2272,14 @@ tests.push(
"type": "module"
}`,
'node_modules/pkg/index.js': ``,
}, {
expectedStderr: `▲ [WARNING] Import "default" will always be undefined because there is no matching export in "node_modules/pkg/index.js" [import-is-undefined]
in.js:3:13:
3 │ if (ns.default !== void 0) throw 'fail'
╵ ~~~~~~~
`,
}),
test(['in.js', '--outfile=node.js', '--bundle', '--external:pkg'], {
'in.js': `
Expand Down

0 comments on commit 220141e

Please sign in to comment.