Skip to content
This repository was archived by the owner on Jun 26, 2023. It is now read-only.

Commit fa9aeeb

Browse files
committed
prepare npm package
1 parent 1d2511e commit fa9aeeb

File tree

4 files changed

+989
-1
lines changed

4 files changed

+989
-1
lines changed

README.md

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,85 @@
11
# babel-plugin-postcss-cssmodules-transform
2-
Babel Plugin Transform PostCSS and extract static CSS
2+
Babel plugin transform and extract PostCSS and CSS Modules to static CSS
3+
4+
### Status
5+
6+
This plugin is still at a very early stage and features are incomplete.
7+
8+
### This plugin does two things:
9+
10+
```JavaScript
11+
// index.js
12+
import styles from './index.module.css'
13+
```
14+
15+
```CSS
16+
/* index.module.css */
17+
.root {
18+
display: flex;
19+
}
20+
```
21+
22+
Into an object that has properties mirroring the styles name in the compiled JS file:
23+
24+
```JavaScript
25+
// index.js
26+
var styles = {"root":"_root_amfqe_1"};
27+
```
28+
29+
And extract to `styles.css`
30+
31+
```CSS
32+
/* styles.css */
33+
._root_amfqe_1 {
34+
display: -webkit-box;
35+
display: -ms-flexbox;
36+
display: flex;
37+
}
38+
```
39+
40+
### Usage
41+
42+
Install from NPM
43+
44+
```sh
45+
$ yarn add @envato/babel-plugin-postcss-cssmodules-transform -D
46+
```
47+
48+
Add the plugin to `.babelrc`.
49+
50+
51+
```JSON
52+
{
53+
"presets": [
54+
["@babel/env", {
55+
"targets": {
56+
"browsers": ["last 2 versions"]
57+
}
58+
}],
59+
"@babel/stage-3",
60+
"@babel/react",
61+
"@babel/typescript"
62+
],
63+
"plugins": [
64+
["@envato/babel-plugin-postcss-cssmodules-transform", {
65+
"extractCss": "./dist/styles.css"
66+
}]
67+
]
68+
}
69+
```
70+
71+
### Todo
72+
73+
- [ ] support `require('./index.module.css')` syntax
74+
- [ ] support `postcss.config.js`
75+
- [ ] unit test
76+
77+
### Alternatives
78+
79+
This plugin is based on the two plugins below, and modified to support `extractCss` option with full `postcss` plugin support.
80+
81+
* [babel-plugin-css-modules-transform](https://github.com/michalkvasnicak/babel-plugin-css-modules-transform)
82+
* [babel-plugin-transform-postcss](https://github.com/wbyoung/babel-plugin-transform-postcss)
83+
84+
### License
85+
MIT

index.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
const { extname, dirname, resolve } = require('path')
2+
const mkdirp = require('mkdirp')
3+
const { readFileSync, appendFileSync } = require('fs')
4+
const deasync = require('deasync')
5+
6+
const postcss = require('postcss')
7+
const atImport = require('postcss-import')
8+
const simpleVars = require('postcss-simple-vars')
9+
const cssNext = require('postcss-cssnext')
10+
const cssModules = require('postcss-modules')
11+
12+
const extensions = ['.css']
13+
14+
const sync = promise => {
15+
let success, error
16+
promise.then(result => (success = { result }), err => (error = err))
17+
deasync.loopWhile(() => !(success || error))
18+
19+
if (!success) {
20+
throw error
21+
}
22+
return success.result
23+
}
24+
25+
const writeCssFile = (targetFilePath, content) => {
26+
mkdirp.sync(dirname(targetFilePath))
27+
appendFileSync(targetFilePath, content, 'utf8')
28+
}
29+
30+
module.exports = function(babel) {
31+
const { types: t } = babel
32+
33+
return {
34+
visitor: {
35+
ImportDeclaration(path, state) {
36+
const { file, opts } = state
37+
const stylesheetPath = path.node.source.value
38+
39+
if (path.node.specifiers.length !== 1) {
40+
return
41+
}
42+
43+
// match `import styles from './index.module.css'` statemenet
44+
if (extensions.indexOf(extname(stylesheetPath)) !== -1) {
45+
const requiringFile = file.opts.filename
46+
const resolvedStylesheetPath = resolve(
47+
process.env.PWD,
48+
dirname(requiringFile),
49+
stylesheetPath
50+
)
51+
52+
const source = readFileSync(resolvedStylesheetPath, 'utf8')
53+
54+
let tokens = {}
55+
const plugins = [
56+
atImport,
57+
simpleVars,
58+
cssNext,
59+
cssModules({
60+
getJSON: function(cssFileName, json, outputFileName) {
61+
tokens = json
62+
}
63+
})
64+
]
65+
// read and process css with `postcss`
66+
const results = sync(
67+
postcss(plugins).process(source, {
68+
from: resolvedStylesheetPath,
69+
to: resolvedStylesheetPath
70+
})
71+
)
72+
const distStylesheetPath = resolve(process.env.PWD, opts.extractCss)
73+
// append all the compiled css into the dist css file
74+
writeCssFile(distStylesheetPath, results.css)
75+
76+
const styles = t.objectExpression(
77+
Object.keys(tokens).map(token =>
78+
t.objectProperty(
79+
t.stringLiteral(token),
80+
t.stringLiteral(tokens[token])
81+
)
82+
)
83+
)
84+
const variableDeclaration = t.VariableDeclaration('var', [
85+
t.VariableDeclarator(path.node.specifiers[0].local, styles)
86+
])
87+
// replace the import statement into `var styles = {}`
88+
path.replaceWith(variableDeclaration)
89+
}
90+
}
91+
}
92+
}
93+
}

package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "@envato/babel-plugin-postcss-cssmodules-transform",
3+
"version": "1.0.0",
4+
"description": "Babel Plugin Transform PostCSS and extract static CSS",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/envato/babel-plugin-postcss-cssmodules-transform.git"
12+
},
13+
"keywords": [
14+
"postcss",
15+
"css-modules",
16+
"babel"
17+
],
18+
"author": "Envato",
19+
"license": "MIT",
20+
"bugs": {
21+
"url": "https://github.com/envato/babel-plugin-postcss-cssmodules-transform/issues"
22+
},
23+
"homepage": "https://github.com/envato/babel-plugin-postcss-cssmodules-transform#readme",
24+
"dependencies": {
25+
"deasync": "^0.1.12",
26+
"mkdirp": "^0.5.1",
27+
"postcss": "^6.0.19",
28+
"postcss-cssnext": "^3.1.0",
29+
"postcss-import": "^11.1.0",
30+
"postcss-modules": "^1.1.0",
31+
"postcss-simple-vars": "^4.1.0"
32+
}
33+
}

0 commit comments

Comments
 (0)