Skip to content

Instantly share code, notes, and snippets.

@finom
Created March 4, 2018 19:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save finom/804b51ba788bc95a9d5ced62b51b34f6 to your computer and use it in GitHub Desktop.
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
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