Created
March 4, 2018 19:17
-
-
Save finom/804b51ba788bc95a9d5ced62b51b34f6 to your computer and use it in GitHub Desktop.
The function enhances postcss import plugin allowing CSS files to @import JS files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const readCache = require('read-cache'); | |
const fs = require('fs'); | |
const { NodeVM, VMScript } = require('vm2'); | |
const optional = require('optional'); | |
/* | |
The function enhances postcss import plugin allowing CSS files to @import JS files | |
which, in their turn, import a valid PostCSS string. | |
Example code: | |
``` | |
// xxx.js | |
export default ` | |
:root { --variable1: red; --variable2: blue; } | |
:global .foo { color: var(--variable1); } | |
`; | |
``` | |
``` | |
// style.css | |
@import "xxx.js"; | |
:global .bar { | |
color: var(--variable2); | |
} | |
``` | |
Usage: | |
The function call needs to be passed to postcss-import plugin as `load` option. | |
```js | |
importPlugin({ | |
load: postCSSImportLoadJSHook({ | |
babelTransformOptions: { | |
presets: ['es2015', 'stage-2'] | |
}, | |
}), | |
}) | |
``` | |
It accepts 2 options: | |
- `useBabel` (`true` by default) enables babel transformation for JS code. | |
If set to false then it uses normal NodeJS environment syntax. | |
- `babelTransformOptions` which allows to pass or override | |
(for example, to enable es2015 modules) Babel options | |
TODO add test cases for: | |
- Normal usage of CSS import | |
- Import with `useBabel = false` | |
- Import with `useBabel = true` | |
+ different `babelTransformOptions` settings | |
+ `export default` | |
+ `module.export` | |
*/ | |
module.exports = function postCSSImportLoadJSHook({ useBabel = true, babelTransformOptions } = {}) { | |
const vmCache = {}; | |
// init VM | |
const vm = new NodeVM(); | |
return (filename) => { | |
// checks is the current file JS file | |
if (/.js$/i.test(filename)) { | |
if (useBabel) { | |
const babelCore = optional('babel-core'); | |
if (!babelCore) { | |
throw new Error('"babel-core" module isn\'t found'); | |
} | |
const { transform } = babelCore; | |
// compile | |
const { code } = transform(fs.readFileSync(filename), babelTransformOptions); | |
// extract cached script if exists | |
const { cachedCode, cachedScript } = vmCache[filename] || {}; | |
// if cached code equals to actual code then assign cached script | |
// else create new script | |
const script = cachedCode && cachedCode === code ? cachedScript : new VMScript(code); | |
// execute | |
const result = vm.run(script); | |
// save results to cache | |
vmCache[filename] = { cachedCode: code, cachedScript: script }; | |
// support for esmodule exports | |
return result.__esModule ? result.default : result; | |
} | |
// if `useBabel = false` require file without pre-compilation | |
// eslint-disable-next-line global-require, import/no-dynamic-require | |
return require(filename); | |
} | |
// if the file isn't a js file then load the file normally (copiled from postcss-import source) | |
return readCache(filename, 'utf-8'); | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment