Skip to content

ESBuild supports "import *.css" in js file but needs outDir as option for js.Build #8411

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

Open
matt9189 opened this issue Apr 13, 2021 · 12 comments
Labels
Milestone

Comments

@matt9189
Copy link

What version of Hugo are you using (hugo version)?

hugo v0.82.0-9D960784

Does this issue reproduce with the latest release?

Yes


As per esbuild:

You can also import CSS from JavaScript. When you do this, esbuild will gather all CSS files referenced from a given entry point and bundle it into a sibling CSS output file next to the JavaScript output file for that JavaScript entry point. So if esbuild generates app.js it would also generate app.css containing all CSS files referenced by app.js.

This is not currently supported with js.Build and results in an error with modules that include an import in the javascript file.
error: Cannot import "entry.css" into a JavaScript file without an output path configured

@matt9189
Copy link
Author

matt9189 commented Apr 14, 2021

This is my first time contributing and I have only been going through the source code for a few hours. I have determined that esbuild is creating the css output file but only if the outputDir has been set, which only occurs when sourceMapExternal is used (the outputDir is never set otherwise which results in esbuild defaulting to WriteToStdOut = true, which throws the error above. Here are some output values from this test:

{{ $js := resources.Get "script.js" | js.Build (dict "sourceMap" "external" ) }}
script.js contains "import a.css"

TargetPath:
OutPath:
OutPath extension replaced: script.js
outFile:
outDir: C:\Users...\AppData\Local\Temp\compileOutput093423083
result.OutputFiles (Paths)
C:\Users...\AppData\Local\Temp\compileOutput093423083\stdin.js.map
C:\Users...\AppData\Local\Temp\compileOutput093423083\stdin.js
C:\Users...\AppData\Local\Temp\compileOutput093423083\stdin.css

I do not know how the context determines the output file and I see there is a separate function for publishing the external map. I am assuming that something similar can be adapted for the css file. Although the whole function may need to be fixed to avoid future issues with other esbuild feature improvements or changes. Not sure, but I am posting this in case it helps anyone work on this issue.

@bep
Copy link
Member

bep commented Apr 15, 2021

What do you use these CSS imports for?

@matt9189
Copy link
Author

matt9189 commented Apr 15, 2021 via email

@bep
Copy link
Member

bep commented Apr 16, 2021

Sure, but why not just import the CSS in the HTML?

I say this because there are several issues that need to be understood before we can do this:

  • The source map implementation was added without too much thinking, thinking that this was mostly a developer utility.
  • But when we now somehow want to import CSS into JS files, we need to think about how that would work with 1) Content inlining (as in do not write the JS files to disk) and 2) Import resolution for CSS files (I assume we could add to what we have) 3) Change detection (the current "rebuild JS files when a JS file is changed" is rather crude, but I have improvements coming for that) 4) Integrity hashing ...

So, your PR looks fine and would work for many, but I'm not prepared to merge that at the moment.

@matt9189
Copy link
Author

As a workaround, I can comment out the import in the module itself, copy the css file to the static folder and import it in the html, but that would only work for me and I may forget to do that if I clone and build my repository elsewhere.

Esbuild would handle the css files; however, it is still a work in progress over there and may not work correctly. If I have two node_modules importing css files, esbuild would concatenate those files into a single css file, but esbuild does not yet support css modules as per their website, so if two files both contain, for instance, body { color: red; }, I'm not sure what esbuild would output as I have not tested. And this is likely to change soon anyways.

So I agree that we wait on the merge but it will have to be addressed in the future or users will be unable to use js.Build with any node_module that has an "import .css" line.

Also, thanks for the quick responses and all the work you put into this project!

@bep
Copy link
Member

bep commented Apr 21, 2021

I have thought a little about this, and I think if we could get these 2 items to work, it would be a good first step:

  1. Add a new option called, say SetOutputPath (default: false)
  2. Adjust resolveComponentInAssets to handle CSS imports the way we handle JS imports (I assume this should work, but I have not tested)

We can discuss the rest in the PR.

@matt9189
Copy link
Author

matt9189 commented Apr 30, 2021

So, because Hugo does not set an outDir in the options passed to esbuild, esbuild sets options.WriteToStdout = true. As esbuild needs to generate two files (js and css), this results in an error when processing the css import. It is not that an outputPath option is needed. Esbuild automatically processes the css file when the import statement is present. Hugo just needs to create a temporary directory for the files and then use the Hugo Context to write them (ctx.To.Write...)

My suggestion to solve the issue would be to include a js.Build option, such as "cssFileName." If left blank, Hugo can, by default, either not create the css file generated by ESBuild or export it in the same way that ESBuild does (i.e. script.js and script.css).

I hope this makes the issue more clear. Also, sorry about delay on response. I took some time to read through the full Hugo resource transformers sections so that I would (hopefully) have a better understanding of the whole system. Anyways, let me know how you think we should proceed and then I will modify the pull request.


I didn't think the issues section was the place to continue this discussion so I created a discourse topic. For whenever you have time: https://discourse.gohugo.io/t/hugo-integration-with-js-build-esbuild-and-multiple-output-files/32647?u=ghostt8117

@schnerring
Copy link

I have encountered this issue when trying to use the babel-plugin-prismjs Babel plugin.

This would make it easy to configure Prism via babel.config.js:

{
  "plugins": [
    ["prismjs", {
        "languages": ["javascript", "css", "markup"],
        "plugins": ["line-numbers"],
        "theme": "twilight",
        "css": true
    }]
  ]
}

The plugin optionally includes the theme's CSS. The CSS is included via import statements but this breaks with js.Build.

This means I need to explicitly include the plugin and theme CSS which defeats the purpose of using the plugin.

@gorootde
Copy link

gorootde commented Jan 1, 2022

Any updates on this?

@arlobelshee
Copy link

Also curious for an update. Any chance this will get changed in the near term? I'm currently having to fall back to webpack for everything, simply because so much JS in the ecosystem imports a css file somewhere. I'd much rather use Hugo pipes!

@lschierer
Copy link

I am hitting this with the adobe coral-spectrum packages.

lschierer added a commit to lschierer/-archive-EvonyTKRTips that referenced this issue Mar 22, 2023
@lschierer
Copy link

In answer to an earlier question, you would want to import the CSS with javascript instead of in the HTML to support light and dark modes that cleanly affect the javascript components. Using the adobe coral-spectrum packages as an example, I would import different css theme files if the site switches from light to dark mode.

@bep bep added this to the v0.131.0 milestone Jul 22, 2024
@bep bep modified the milestones: v0.131.0, v0.133.0 Aug 9, 2024
@cmahnke cmahnke mentioned this issue Aug 21, 2024
@bep bep modified the milestones: v0.133.0, Unscheduled Aug 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants