Skip to content

Commit

Permalink
css: use local-css for .module.css files (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Aug 8, 2023
1 parent be9f8e5 commit 727e5ff
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 34 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@

Note that using this feature means esbuild will potentially do a lot of file system I/O to find all possible files that might match the pattern. This is by design, and is not a bug. If this is a concern, I recommend either avoiding the `/**/` pattern (e.g. by not putting a `/` before a wildcard) or using this feature only in directory subtrees which do not have many files that don't match the pattern (e.g. making a subdirectory for your JSON files and explicitly including that subdirectory in the pattern).
* Use the `local-css` loader for `.module.css` files by default ([#20](https://github.com/evanw/esbuild/issues/20))
With this release the `css` loader is still used for `.css` files except that `.module.css` files now use the `local-css` loader. This is a common convention in the web development community. If you need `.module.css` files to use the `css` loader instead, then you can override this behavior with `--loader:.module.css=css`.
## 0.18.20
* Support advanced CSS `@import` rules ([#953](https://github.com/evanw/esbuild/issues/953), [#3137](https://github.com/evanw/esbuild/issues/3137))
Expand Down
25 changes: 13 additions & 12 deletions internal/bundler/bundler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2552,18 +2552,19 @@ func (s *scanner) validateTLA(sourceIndex uint32) tlaCheck {

func DefaultExtensionToLoaderMap() map[string]config.Loader {
return map[string]config.Loader{
"": config.LoaderJS, // This represents files without an extension
".js": config.LoaderJS,
".mjs": config.LoaderJS,
".cjs": config.LoaderJS,
".jsx": config.LoaderJSX,
".ts": config.LoaderTS,
".cts": config.LoaderTSNoAmbiguousLessThan,
".mts": config.LoaderTSNoAmbiguousLessThan,
".tsx": config.LoaderTSX,
".css": config.LoaderCSS,
".json": config.LoaderJSON,
".txt": config.LoaderText,
"": config.LoaderJS, // This represents files without an extension
".js": config.LoaderJS,
".mjs": config.LoaderJS,
".cjs": config.LoaderJS,
".jsx": config.LoaderJSX,
".ts": config.LoaderTS,
".cts": config.LoaderTSNoAmbiguousLessThan,
".mts": config.LoaderTSNoAmbiguousLessThan,
".tsx": config.LoaderTSX,
".css": config.LoaderCSS,
".module.css": config.LoaderLocalCSS,
".json": config.LoaderJSON,
".txt": config.LoaderText,
}
}

Expand Down
40 changes: 20 additions & 20 deletions internal/bundler_tests/snapshots/snapshots_css.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1810,17 +1810,17 @@ TestIgnoreURLsInAtRulePrelude
TestImportCSSFromJSComposes
---------- /out/entry.js ----------
// styles.module.css
var styles_module_default = {
local0: "GLOBAL1 GLOBAL2 styles_module_local4 styles_module_local3 styles_module_local1 GLOBAL3 styles_module_local2 GLOBAL4 styles_module_local0",
local1: "styles_module_local4 styles_module_local3 styles_module_local1",
local2: "styles_module_local2",
local3: "styles_module_local4 styles_module_local3",
local4: "styles_module_local4",
fromOtherFile: "base_module_base1 base_module_base2 other1_module_local0 base_module_base3 other2_module_local0 styles_module_fromOtherFile"
var styles_default = {
local0: "GLOBAL1 GLOBAL2 styles_local4 styles_local3 styles_local1 GLOBAL3 styles_local2 GLOBAL4 styles_local0",
local1: "styles_local4 styles_local3 styles_local1",
local2: "styles_local2",
local3: "styles_local4 styles_local3",
local4: "styles_local4",
fromOtherFile: "base_base1 base_base2 other1_local0 base_base3 other2_local0 styles_fromOtherFile"
};

// entry.js
console.log(styles_module_default);
console.log(styles_default);

---------- /out/entry.css ----------
/* global.css */
Expand All @@ -1829,44 +1829,44 @@ console.log(styles_module_default);
}

/* other1.module.css */
.other1_module_local0 {
.other1_local0 {
color: blue;
}

/* base.module.css */
.base_module_base1 {
.base_base1 {
cursor: pointer;
}
.base_module_base2 {
.base_base2 {
display: inline;
}
.base_module_base3 {
.base_base3 {
float: left;
}

/* other2.module.css */
.other2_module_local0 {
.other2_local0 {
background: purple;
}

/* styles.module.css */
.styles_module_local0 {
.styles_local0 {
}
.styles_module_local0 {
.styles_local0 {
background: green;
}
.styles_module_local0 {
.styles_local0 {
}
.styles_module_local3 {
.styles_local3 {
border: 1px solid black;
}
.styles_module_local4 {
.styles_local4 {
opacity: 0.5;
}
.styles_module_local1 {
.styles_local1 {
color: red;
}
.styles_module_fromOtherFile {
.styles_fromOtherFile {
}

================================================================================
Expand Down
13 changes: 12 additions & 1 deletion internal/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,18 @@ func PlatformIndependentPathDirBaseExt(path string) (dir string, base string, ex

// Strip off the extension
if dot := strings.LastIndexByte(base, '.'); dot >= 0 {
base, ext = base[:dot], base[dot:]
ext = base[dot:]

// We default to the "local-css" loader for ".module.css" files. Make sure
// the string names generated by this don't all have "_module_" in them.
if ext == ".css" {
if dot2 := strings.LastIndexByte(base[:dot], '.'); dot2 >= 0 && base[dot2:] == ".module.css" {
dot = dot2
ext = base[dot:]
}
}

base = base[:dot]
}
return
}
Expand Down
38 changes: 37 additions & 1 deletion scripts/end-to-end-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -7845,7 +7845,7 @@ tests.push(
}),
)

// Test CSS-related warning ranges
// Tests for CSS modules
tests.push(
test(['in.js', '--outfile=node.js', '--bundle', '--loader:.css=local-css'], {
'in.js': `
Expand All @@ -7871,6 +7871,42 @@ tests.push(
`,
}),
test(['in.js', '--outfile=node.js', '--bundle'], {
'in.js': `
import * as foo_styles from "./foo.css"
import * as bar_styles from "./bar"
const { foo } = foo_styles
const { bar } = bar_styles
if (foo !== void 0) throw 'fail: foo=' + foo
if (bar !== void 0) throw 'fail: bar=' + bar
`,
'foo.css': `.foo { color: red }`,
'bar.css': `.bar { color: green }`,
}),
test(['in.js', '--outfile=node.js', '--bundle'], {
'in.js': `
import * as foo_styles from "./foo.module.css"
import * as bar_styles from "./bar.module"
const { foo } = foo_styles
const { bar } = bar_styles
if (foo !== 'foo_foo') throw 'fail: foo=' + foo
if (bar !== 'bar_bar') throw 'fail: bar=' + bar
`,
'foo.module.css': `.foo { color: red }`,
'bar.module.css': `.bar { color: green }`,
}),
test(['in.js', '--outfile=node.js', '--bundle', '--loader:.module.css=css'], {
'in.js': `
import * as foo_styles from "./foo.module.css"
import * as bar_styles from "./bar.module"
const { foo } = foo_styles
const { bar } = bar_styles
if (foo !== void 0) throw 'fail: foo=' + foo
if (bar !== void 0) throw 'fail: bar=' + bar
`,
'foo.module.css': `.foo { color: red }`,
'bar.module.css': `.bar { color: green }`,
}),
)

// Test writing to stdout
Expand Down

0 comments on commit 727e5ff

Please sign in to comment.