Skip to content
This repository was archived by the owner on Jan 18, 2022. It is now read-only.

Commit aafdbc3

Browse files
authored
✨ CSS Modules (#57)
* ✨ CSS Modules * Add CSS modules before compiling * Add scss support * Add support for pug & jade Fix #43 * Circle yarn issue
1 parent f17a1ba commit aafdbc3

28 files changed

+1323
-116
lines changed

.babelrc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"presets": [
3+
[ "es2015", { "modules": false }],
4+
"stage-2"
5+
],
6+
"plugins": ["transform-runtime"],
7+
"retainLines": true,
8+
"comments": true
9+
}

circle.yml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dependencies:
1111
- composer global require --no-progress sereno/installer
1212
override:
1313
- yarn --no-progress
14+
- npm rebuild node-sass
1415
cache_directories:
1516
- "~/.yarn-cache"
1617
- "~/.composer/cache"

config/build.js

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
22

3-
const buble = require('rollup-plugin-buble');
3+
const babel = require('rollup-plugin-babel');
44
const rollup = require('rollup');
55
const replace = require('rollup-plugin-replace');
66
const zlib = require('zlib');
@@ -17,12 +17,7 @@ fs.writeFileSync('src/index.js', main);
1717
rollup.rollup({
1818
entry: 'src/index.js',
1919
plugins: [
20-
buble({
21-
objectAssign: 'Object.assign',
22-
transforms: {
23-
dangerousForOf: true
24-
}
25-
})
20+
babel({ runtimeHelpers: true })
2621
]
2722
})
2823
.then(function (bundle) {

package.json

+10
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,23 @@
4141
"debug": "^2.6.0",
4242
"html-minifier": "^3.2.3",
4343
"magic-string": "^0.19.0",
44+
"node-sass": "^4.5.0",
4445
"parse5": "^3.0.1",
46+
"postcss": "^5.2.11",
47+
"postcss-modules": "^0.6.4",
48+
"posthtml": "^0.9.2",
49+
"posthtml-attrs-parser": "^0.1.1",
50+
"pug": "^2.0.0-beta10",
4551
"rollup-pluginutils": "^2.0.1",
4652
"vue-template-compiler": "^2.1.10",
4753
"vue-template-es2015-compiler": "^1.5.0",
4854
"vue-template-validator": "^1.1.5"
4955
},
5056
"devDependencies": {
5157
"babel-eslint": "^7.1.1",
58+
"babel-plugin-transform-runtime": "^6.22.0",
59+
"babel-preset-es2015": "^6.22.0",
60+
"babel-preset-stage-2": "^6.22.0",
5261
"clean-css": "^3.4.24",
5362
"coveralls": "^2.11.15",
5463
"eslint": "^3.14.0",
@@ -63,6 +72,7 @@
6372
"mocha": "^3.2.0",
6473
"mocha-lcov-reporter": "^1.2.0",
6574
"rollup": "^0.41.4",
75+
"rollup-plugin-babel": "^2.7.1",
6676
"rollup-plugin-buble": "^0.15.0",
6777
"rollup-plugin-css-only": "^0.2.0",
6878
"rollup-plugin-replace": "^1.1.1",

src/index.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createFilter } from 'rollup-pluginutils'
22

33
import vueTransform from './vueTransform'
44
import DEFAULT_OPTIONS from './options'
5-
import compileStyle from './style'
5+
import compileStyle from './style/index'
66
import debug from './debug'
77

88
function mergeOptions (options, defaults) {
@@ -68,13 +68,14 @@ export default function vue (options = {}) {
6868
return styles[component][index] || ''
6969
}
7070
},
71-
transform (source, id) {
71+
async transform (source, id) {
7272
if (!filter(id) || !id.endsWith('.vue')) {
7373
debug(`Ignore: ${id}`)
7474
return null
7575
}
7676

77-
const { code, css, map } = vueTransform(source, id, options)
77+
const { code, css, map } = await vueTransform(source, id, options)
78+
7879
styles[id] = css
7980

8081
return { code, map }

src/options.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,12 @@ export default {
3434
unicodeRegExp: false
3535
}
3636
},
37-
styleToImports: false
37+
styleToImports: false,
38+
autoStyles: true,
39+
disableCssModuleStaticReplacement: false,
40+
modules: {
41+
generateScopedName: '[name]__[local]___[hash:base64:5]'
42+
},
43+
scss: {},
44+
pug: {}
3845
}

src/style.js

-41
This file was deleted.

src/style/css.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import postcss from 'postcss'
2+
import modules from 'postcss-modules'
3+
4+
function compileModule (code, map, source, options) {
5+
let style
6+
7+
return postcss([
8+
modules({
9+
getJSON (filename, json) {
10+
style = json
11+
},
12+
...options.modules
13+
})
14+
]).process(code, { map: { inline: false, prev: map }, from: source.id, to: source.id })
15+
.then(
16+
result => ({ code: result.css, map: result.map, module: style }),
17+
error => {
18+
throw error
19+
})
20+
}
21+
22+
export default async function (promise, options) {
23+
const style = await promise
24+
const { code, map } = ('$compiled' in style) ? style.$compiled : style
25+
26+
if (style.module === true) {
27+
return compileModule(code, map, style, options).then(compiled => {
28+
if (style.$compiled) {
29+
compiled.$prev = style.$compiled
30+
}
31+
32+
style.$compiled = compiled
33+
34+
return style
35+
})
36+
}
37+
38+
const output = { code, map, lang: 'css' }
39+
40+
if (style.$compiled) output.$prev = style.$compiled
41+
42+
style.$compiled = output
43+
44+
return style
45+
}

src/style/index.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { writeFile } from 'fs'
2+
import compileCSS from './css'
3+
import compileSCSS from './scss'
4+
5+
const compilers = {
6+
scss: compileSCSS,
7+
sass: compileSCSS
8+
}
9+
10+
export async function compile (style, options) {
11+
let output
12+
13+
if (style.lang === 'css') {
14+
output = await compileCSS(style, options)
15+
} else {
16+
output = await compileCSS(await compilers[style.lang].call(null, style, options), options)
17+
}
18+
19+
return output
20+
}
21+
22+
export default function (files, options) {
23+
if (options.css === false) {
24+
return
25+
}
26+
27+
// Combine all stylesheets.
28+
let css = ''
29+
const allStyles = []
30+
31+
Object.keys(files).forEach((file) => {
32+
files[file].forEach((style) => {
33+
css += style.code + '\n'
34+
allStyles.push(style)
35+
})
36+
})
37+
38+
// Emit styles through callback
39+
if (typeof (options.css) === 'function') {
40+
options.css(css, allStyles, compile)
41+
42+
return
43+
}
44+
45+
// Don't generate empty style file.
46+
if (!css.trim().length) {
47+
return
48+
}
49+
50+
const dest = options.css
51+
52+
if (typeof dest !== 'string') {
53+
return
54+
}
55+
56+
// Emit styles to file
57+
writeFile(dest, css, (err) => {
58+
if (err) throw err
59+
})
60+
}

src/style/scss.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import sass from 'node-sass'
2+
3+
export default function (style, options) {
4+
const { css, map } = sass.renderSync({
5+
file: style.id,
6+
data: style.code,
7+
omitSourceMapUrl: true,
8+
sourceMap: true,
9+
outFile: style.id,
10+
...options.scss
11+
})
12+
13+
style.$compiled = {
14+
code: css.toString(),
15+
map: map.toString()
16+
}
17+
18+
return style
19+
}

src/template/html.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import postHtml from 'posthtml'
2+
import parseAttrs from 'posthtml-attrs-parser'
3+
4+
const plugin = (modules) => {
5+
return function cssModules (tree) {
6+
tree.match({attrs: {'class': /\w+/}}, node => {
7+
const attrs = parseAttrs(node.attrs)
8+
9+
if (attrs.class) {
10+
attrs.class = attrs.class.map(c => modules[c] || c)
11+
12+
node.attrs = attrs.compose()
13+
}
14+
15+
return node
16+
})
17+
}
18+
}
19+
20+
export default async function (template, extras, options) {
21+
if ('modules' in extras && Object.keys(extras.modules).length) {
22+
const output = await postHtml([
23+
plugin(extras.modules)
24+
]).process(template)
25+
26+
return output.html
27+
}
28+
29+
return template
30+
}

src/template/index.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import compileHTML from './html'
2+
import compilePug from './pug'
3+
4+
const compilers = {
5+
html: compileHTML,
6+
pug: compilePug,
7+
jade: compilePug
8+
}
9+
10+
export default async function (template, extras, options) {
11+
return await compilers[extras.lang || 'html'].call(null, template, extras, options)
12+
}

src/template/pug.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import pug from 'pug'
2+
3+
export default async function (template, extras, options) {
4+
const compiler = pug.compile(template, { filename: extras.id, ...options.pug })
5+
6+
return compiler({css: extras.modules || {}})
7+
}

0 commit comments

Comments
 (0)