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

support postcss #125

Merged
merged 1 commit into from
Sep 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"merge-options": "0.0.64",
"parse5": "^2.1.0",
"postcss": "^5.2.11",
"postcss-load-config": "^1.2.0",
"postcss-modules": "^0.6.4",
"postcss-selector-parser": "^2.2.3",
"posthtml": "^0.9.2",
Expand All @@ -55,6 +56,7 @@
"vue-template-validator": "^1.1.5"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-eslint": "^7.1.1",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-preset-es2015": "^6.22.0",
Expand Down
3 changes: 3 additions & 0 deletions src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ export default {
// Config for stylus.
stylus: {},

// Config for postcss.
postcss: {},

// Config for pug compiler.
pug: {},

Expand Down
135 changes: 65 additions & 70 deletions src/style/css.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import postcss from 'postcss'
import postcssLoadConfig from './postcss'
import modules from 'postcss-modules'
import selectorParser from 'postcss-selector-parser'
import camelcase from 'camelcase'
Expand All @@ -21,7 +22,7 @@ function isInvalidTag (tag) {
}
}

const addScopeID = postcss.plugin('add-scope-id', options => {
const addScopeID = postcss.plugin('add-scope-id', ({ scopeID }) => {
const selectorTransformer = selectorParser(selectors => {
selectors.each(selector => {
let target = null
Expand Down Expand Up @@ -55,7 +56,7 @@ const addScopeID = postcss.plugin('add-scope-id', options => {
/* eslint-enable complexity */

target && selector.insertAfter(target, selectorParser.attribute({
attribute: options.scopeID
attribute: scopeID
}))
})
})
Expand All @@ -78,25 +79,9 @@ function compileModule (code, map, source, options) {
},
...options.cssModules
})
]).process(code, { map: { inline: false, prev: map }, from: source.id, to: source.id })
.then(
result => ({ code: result.css, map: result.map.toString(), module: style }),
error => {
throw error
}
)
}

function compileScopedCSS (code, map, source, options) {
debug(`Scoped CSS: ${source.id}`)

return postcss([
addScopeID({
scopeID: genScopeID(source.id)
})
]).process(code, { map: { inline: false, prev: map }, from: source.id, to: source.id })
.then(
result => ({ code: result.css, map: result.map.toString() }),
result => ({ code: result.css, map: result.map.toString(), module: style }),
error => {
throw error
}
Expand All @@ -110,62 +95,72 @@ function escapeRegExp (str) {
export default async function (promise, options) {
const style = await promise
debug(`CSS: ${style.id}`)
const { code, map } = ('$compiled' in style) ? style.$compiled : style

if (style.module === true) {
return compileModule(code, map, style, options).then(compiled => {
if (style.$compiled) {
compiled.$prev = style.$compiled

const classes = Object.keys(compiled.module)
const cssModule = {}

if (classes.length) {
// Apply CSS modules to actual source.
// TODO: Update source map.
// const original = style.code

style.code = classes.reduce(
(result, original) => {
const transformed = compiled.module[original]
cssModule[camelcase(original)] = transformed
cssModule[original] = transformed

return result.replace(new RegExp(escapeRegExp(`.${original}`), 'g'), `.${transformed}`)
},
style.code
)
// style.map = (new MagicString(original))

compiled.module = (
typeof (style.module) === 'string' && style.attrs.module.length
) ? { [style.module]: cssModule } : cssModule
}
}

style.$compiled = compiled

return style
}).catch(error => debug(error))
const {code, map} = ('$compiled' in style) ? style.$compiled : style
const initPostcssOptions = {map: {inline: false, prev: map}, from: style.id, to: style.id}
const hasModule = style.module === true
const hasScope = style.scoped === true
const postcssConfig = await postcssLoadConfig(options.postcss)
const plugins = postcssConfig.plugins || []
let processPromise = Promise.resolve()

if (hasScope) {
debug(`Scoped CSS: ${style.id}`)
plugins.push(addScopeID({
scopeID: genScopeID(style.id)
}))
}

if (style.scoped === true) {
return compileScopedCSS(code, map, style, options).then(compiled => {
if (style.$compiled) {
compiled.$prev = style.$compiled
}

style.$compiled = compiled

return style
})
if (hasModule) {
// TODO: I found this plugin makes all postcss plugin run twice.
processPromise = compileModule(code, map, style, options)
}

const output = { code, map, lang: 'css' }
const curOptions = Object.assign({}, postcssConfig.options, initPostcssOptions)

if (style.$compiled) output.$prev = style.$compiled
return processPromise.then(firstResult => {
const moduleNames = firstResult && firstResult.module
return postcss(plugins)
.process(firstResult ? firstResult.code : code, curOptions)
.then(result => {
const compiled = {
code: result.css,
map: result.map.toString()
}
if (style.$compiled) {
compiled.$prev = style.$compiled
}

style.$compiled = output
if (hasModule) {
const classes = Object.keys(moduleNames)
const cssModule = {}

if (classes.length) {
// Apply CSS modules to actual source.
// TODO: Update source map.
// const original = style.code

style.code = classes.reduce(
(result, original) => {
const transformed = moduleNames[original]
cssModule[camelcase(original)] = transformed
cssModule[original] = transformed

return result.replace(new RegExp(escapeRegExp(`.${original}`), 'g'), `.${transformed}`)
},
style.code
)
// style.map = (new MagicString(original))

compiled.module = (
typeof (style.module) === 'string' && style.attrs.module.length
) ? {[style.module]: cssModule} : cssModule
}
}

style.$compiled = compiled

return style
return style
})
.catch(error => debug(error))
})
}
25 changes: 25 additions & 0 deletions src/style/postcss.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import postcssrc from 'postcss-load-config'

export default async function (postcssOpt) {
let options = {}
let plugins = []

if (typeof postcssOpt === 'function') {
plugins = postcssOpt.call(this)
} else if (Array.isArray(postcssOpt)) {
plugins = plugins.concat(postcssOpt)
} else if (typeof postcssOpt === 'object') {
options = Object.assign({}, options, postcssOpt)
}

return postcssrc().then((config) => {
if (config.plugins) {
plugins = plugins.concat(config.plugins)
}

if (config.options) {
options = Object.assign(options, config.options)
}
return {plugins, options}
}).catch(() => { return {plugins, options} })
}
6 changes: 6 additions & 0 deletions test/expects/postcss.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

body {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
3 changes: 3 additions & 0 deletions test/expects/postcss.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var postcss = {};

export default postcss;
17 changes: 15 additions & 2 deletions test/expects/scoped-css-with-deep-tag.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
background-color: red;
}

@keyframes test {
@-webkit-keyframes test {
0% {
color: red;
}
Expand All @@ -19,4 +19,17 @@
color: yellow;
}
}


@keyframes test {
0% {
color: red;
}

50% {
color: green;
}

100% {
color: yellow;
}
}
8 changes: 8 additions & 0 deletions test/fixtures/postcss.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
export default {}
</script>
<style>
body {
display: flex;
}
</style>
38 changes: 20 additions & 18 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var assert = require('assert')
var fs = require('fs')
var rollup = require('rollup')
var path = require('path')
var autoprefixer = require('autoprefixer')

process.chdir(__dirname)

Expand Down Expand Up @@ -33,6 +34,7 @@ function test(name) {
modules: {
generateScopedName: '[name]__[local]'
},
postcss: [autoprefixer()],
compileTemplate: [
'compileTemplate',
'compileTemplateLocalComponent',
Expand All @@ -49,23 +51,24 @@ function test(name) {

// Check css output
if ([
'css-modules',
'css-modules-static',
'import-scss',
'import-less',
'less',
'pug',
'scoped-css',
'scoped-css-with-no-auto-style',
'scoped-css-with-deep-tag',
'scss',
'sass',
'pug',
'less',
'style',
'stylus',
'external-script'
].indexOf(name) > -1) {
'css-modules',
'css-modules-static',
'import-scss',
'import-less',
'less',
'pug',
'scoped-css',
'scoped-css-with-no-auto-style',
'scoped-css-with-deep-tag',
'scss',
'sass',
'pug',
'less',
'style',
'stylus',
'external-script',
'postcss'
].indexOf(name) > -1) {
var css = read('expects/' + name + '.css')
assert.equal(css.trim(), actualCss.trim(), 'should output style tag content')
} else if (['no-css-extract'].indexOf(name) > -1) {
Expand Down Expand Up @@ -114,4 +117,3 @@ describe('styleToImports', function () {
})
})
})

Loading