Is there any way to make webpack to apply it's loaders to just a portion of a file? Here's a example of what I mean...
Let's say I have a bunch of loaders configured for .scss
files. Would be awesome to be able write a component in any of the two following ways to produce the same output:
1) Standard loaders
component.js
import './component.scss';
export class Component {
...
component.scss
.component {
background: #663399
}
...
2) Custom loaders
component.js
my-magic-import `
.component {
background: #663399
}
`
export class Component {
...
How could I achieve something similar to the second case?
Could I somehow modify the way webpack identify the requires
, imports
and file extensions so it could be able to understand my custom syntax?
As last resort could one write a loader for js files that do this job for me?
Thanks for any hints about what should I read about to get this done.
You could try using these 2 libraries with webpack to convert to a cssobj first, then to plain CSS after that.
https://github.com/cssobj/cssobj-converter (supports sass/less)
var converter = require('cssobj-converter')
var obj = converter('p { color: red; }') //obj is a css object
https://github.com/cssobj/cssobj
var cssobj = require('cssobj')
var result = cssobj(obj) // the result is a CSS string
You can write a globally unique function __insertCSS
(in your app's index.js) which inserts plain CSS strings in the head
element.
Now these libraries only run on node, so you need one more step to make it work in the browser: a string replacement plugin
https://www.npmjs.com/package/string-replace-webpack-plugin
In webpack config you should configure the replace plugin to search for a pattern like /__insertCSS\(.*?\)/
, get the string argument, process it like shown above and replace it with the result.
In your webpack config:
var StringReplacePlugin = require("string-replace-webpack-plugin");
var converter = require('cssobj-converter')
var cssobj = require('cssobj')
function parseSass(str){
var obj = converter(str) //obj is a css object
return cssobj(obj) // the result is a CSS string
}
...in module
:
loaders: [
// configure replacements for file patterns
{
test: /\.js(x?)$/,
loader: StringReplacePlugin.replace({
replacements: [
{
pattern: /__insertCSS\(`(.*?)`\)/ig,
replacement: function (match, p1, offset, string) {
//p1 is the string enclosed by backticks
var cssStr = parseSass(p1);
//need to escape quotes with JSON in resulting string
return '__insertCSS("' + JSON.stringify(cssStr) + '")'
}
}
]})
}
]
Mind you, I have not tested that, but it seems feasible at a first look.
This string replacement loader must come before babel, just put it first in the loaders
array
Doc here: https://webpack.github.io/docs/loaders.html#loader-order