styled-jsx icon indicating copy to clipboard operation
styled-jsx copied to clipboard

Resolve urls inside separate css-files

Open germansokolov13 opened this issue 5 years ago • 6 comments

Do you want to request a feature or report a bug?

Request a feature or request docs addition

Images in url() do not resolve if separate css-files setup is used.

https://github.com/zeit/styled-jsx#styles-in-regular-css-files Here it is documented how to use separate files for styles. However if we do that we can no longer insert images resolved by Webpack.

I tried to use css-loader but then the styles are rendered in such a way that it won't work at all.

Are there any plans or ideas how to handle this properly? Css inside components doesn't seem right but images have to be handled with Webpack. Normally there are some means to parse them out of url(). Without Webpack I can't use image loaders like those that encode images in base64. Without separate files I can't use IDE css helping tools. Something is off.

I ended up rolling my own Webpack loader to handle this but it seems like too much complexity.

germansokolov13 avatar Nov 08 '19 15:11 germansokolov13

Do you know how other projects do this with loaders and such? Eg. if you have a sass project and build it with webpack (no styled-jsx). How do you solve this issue?

giuseppeg avatar Nov 28 '19 16:11 giuseppeg

I think in majority of frontend projects that use Webpack css-loader is always used. This loader is the one responsible for resolving url()s in css-files. But css-loader does something else too while doing this. Its output is somehow incompatible with styled-jsx.

Most often other projects use a combination of style-loader and css-loader called at the very end of styles processing. I.e. first different kinds of loaders like sass and so on are called. css-loader is always the last but one being called. And style-loader is normally the last one.

But I do not know how to integrate it with styled-jsx

germansokolov13 avatar Nov 28 '19 19:11 germansokolov13

Yes the styled-jsx loader turns CSS into JavaScript, so the url resolving should be done earlier. Have you tried to run your CSS through https://www.npmjs.com/package/resolve-url-loader before passing it to the styled-jsx's loader?

giuseppeg avatar Nov 29 '19 07:11 giuseppeg

I tried now. If invoked before styledJsxLoader it seems to do nothing for some reason. Urls remain unchanged. If invoked after styledJsxLoader then error occurrs during build: Error: resolve-url-loader: CSS error <path to my file>: Unknown word.

I am not sure how this loader works. I used it without any options. Maybe it should configured somehow.

germansokolov13 avatar Nov 29 '19 08:11 germansokolov13

I was having the same issue, ended up creating my own custom loader:

function isAbsolutePath(url) {
  return /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(url)
}

module.exports = function (content) {
  if (this.cacheable) this.cacheable()
  this.addDependency(this.resourcePath)

  let index = 0
  let imports = ''
  const output = content.replace(/(?:url(?:\s+)?)\((?:'|")?(.*[^'"])(?:'|")?\)/gi, (...args) => {
    const url = args[1]
    if (isAbsolutePath(url)) {
      return args[0]
    }
    const name = `_temp_url_${index}`
    const nameAsVar = '${' + name + '}'
    imports = `${imports} import ${name} from '${url}';`
    index++
    return `url("${nameAsVar}")`
  })

  this.callback(null, `${imports} ${output}`)
}

Put this loader in between styled-jsx/webpack and options.defaultLoaders.babel (if you are using next.js) something like this:

config.module.rules.push({
  test: /\.scss$/,
  use: [
    options.defaultLoaders.babel,
    {
      loader: path.join(__dirname, './lib/styled-jsx-url-loader'),
    },
    {
      loader: require('styled-jsx/webpack').loader,
      options: {
        type: 'scoped',
      },
    },
  ],
})

It's not sure sophisticated, basically just one big regexp replace so there could be some false positives, but it does the job for me.

danielhusar avatar Apr 29 '20 22:04 danielhusar

I made also a loader for that https://github.com/danielhusar/styled-jsx-url-loader

danielhusar avatar May 04 '20 17:05 danielhusar