chushihua
This commit is contained in:
+79
@@ -0,0 +1,79 @@
|
||||
const postcss = require('postcss')
|
||||
const loaderUtils = require('loader-utils')
|
||||
const loadPostcssConfig = require('./load-postcss-config')
|
||||
|
||||
const trim = require('./plugins/trim')
|
||||
const scopeId = require('./plugins/scope-id')
|
||||
|
||||
module.exports = function (css, map) {
|
||||
this.cacheable()
|
||||
const cb = this.async()
|
||||
|
||||
const query = loaderUtils.getOptions(this) || {}
|
||||
let vueOptions = this.options.__vueOptions__
|
||||
|
||||
if (!vueOptions) {
|
||||
if (query.hasInlineConfig) {
|
||||
this.emitError(
|
||||
`\n [vue-loader] It seems you are using HappyPack with inline postcss ` +
|
||||
`options for vue-loader. This is not supported because loaders running ` +
|
||||
`in different threads cannot share non-serializable options. ` +
|
||||
`It is recommended to use a postcss config file instead.\n` +
|
||||
`\n See http://vue-loader.vuejs.org/en/features/postcss.html#using-a-config-file for more details.\n`
|
||||
)
|
||||
}
|
||||
vueOptions = Object.assign({}, this.options.vue, this.vue)
|
||||
}
|
||||
|
||||
loadPostcssConfig(this, vueOptions.postcss)
|
||||
.then(config => {
|
||||
const plugins = config.plugins.concat(trim)
|
||||
const options = Object.assign(
|
||||
{
|
||||
to: this.resourcePath,
|
||||
from: this.resourcePath,
|
||||
map: false
|
||||
},
|
||||
config.options
|
||||
)
|
||||
|
||||
// add plugin for vue-loader scoped css rewrite
|
||||
if (query.scoped) {
|
||||
plugins.push(scopeId({ id: query.id }))
|
||||
}
|
||||
|
||||
// source map
|
||||
if (
|
||||
this.sourceMap &&
|
||||
!this.minimize &&
|
||||
vueOptions.cssSourceMap !== false &&
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
!options.map
|
||||
) {
|
||||
options.map = {
|
||||
inline: false,
|
||||
annotation: false,
|
||||
prev: map
|
||||
}
|
||||
}
|
||||
|
||||
return postcss(plugins)
|
||||
.process(css, options)
|
||||
.then(result => {
|
||||
if (result.messages) {
|
||||
result.messages.forEach(({ type, file }) => {
|
||||
if (type === 'dependency') {
|
||||
this.addDependency(file)
|
||||
}
|
||||
})
|
||||
}
|
||||
const map = result.map && result.map.toJSON()
|
||||
cb(null, result.css, map)
|
||||
return null // silence bluebird warning
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
cb(e)
|
||||
})
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
const load = require('postcss-load-config')
|
||||
|
||||
let loaded
|
||||
|
||||
function isObject (val) {
|
||||
return val && typeof val === 'object'
|
||||
}
|
||||
|
||||
module.exports = function loadPostcssConfig (loaderContext, inlineConfig = {}) {
|
||||
if (inlineConfig.useConfigFile === false) {
|
||||
return Promise.resolve({
|
||||
plugins: inlineConfig.plugins || [],
|
||||
options: inlineConfig.options || {}
|
||||
})
|
||||
}
|
||||
|
||||
if (process.env.VUE_LOADER_TEST || !loaded) {
|
||||
const config = inlineConfig.config || {}
|
||||
const ctx = { webpack: loaderContext }
|
||||
if (config.ctx) {
|
||||
ctx.options = config.ctx
|
||||
}
|
||||
loaded = load(ctx, config.path, { argv: false }).catch(err => {
|
||||
// postcss-load-config throws error when no config file is found,
|
||||
// but for us it's optional. only emit other errors
|
||||
if (err.message.indexOf('No PostCSS Config found') >= 0) {
|
||||
return
|
||||
}
|
||||
const friendlyErr = new Error(`Error loading PostCSS config: ${err.message}`)
|
||||
Error.captureStackTrace(friendlyErr, err)
|
||||
loaderContext.emitError(friendlyErr)
|
||||
})
|
||||
}
|
||||
|
||||
return loaded.then(config => {
|
||||
let plugins = []
|
||||
let options = {}
|
||||
|
||||
// inline postcss options for vue-loader
|
||||
if (typeof inlineConfig === 'function') {
|
||||
inlineConfig = inlineConfig.call(this, this)
|
||||
}
|
||||
if (Array.isArray(inlineConfig)) {
|
||||
plugins = inlineConfig
|
||||
} else if (isObject(inlineConfig)) {
|
||||
plugins =
|
||||
typeof inlineConfig.plugins === 'function'
|
||||
? inlineConfig.plugins.call(this, this)
|
||||
: inlineConfig.plugins || []
|
||||
options = inlineConfig.options || {}
|
||||
}
|
||||
|
||||
// merge postcss config file
|
||||
if (config && config.plugins) {
|
||||
plugins = plugins.concat(config.plugins)
|
||||
}
|
||||
if (config && config.options) {
|
||||
options = Object.assign({}, config.options, options)
|
||||
}
|
||||
|
||||
return {
|
||||
plugins,
|
||||
options
|
||||
}
|
||||
})
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
const postcss = require('postcss')
|
||||
const selectorParser = require('postcss-selector-parser')
|
||||
|
||||
module.exports = postcss.plugin('add-id', ({ id }) => root => {
|
||||
const keyframes = Object.create(null)
|
||||
|
||||
root.each(function rewriteSelector (node) {
|
||||
if (!node.selector) {
|
||||
// handle media queries
|
||||
if (node.type === 'atrule') {
|
||||
if (node.name === 'media' || node.name === 'supports') {
|
||||
node.each(rewriteSelector)
|
||||
} else if (/-?keyframes$/.test(node.name)) {
|
||||
// register keyframes
|
||||
keyframes[node.params] = node.params = node.params + '-' + id
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
node.selector = selectorParser(selectors => {
|
||||
selectors.each(selector => {
|
||||
let node = null
|
||||
selector.each(n => {
|
||||
// ">>>" combinator
|
||||
if (n.type === 'combinator' && n.value === '>>>') {
|
||||
n.value = ' '
|
||||
n.spaces.before = n.spaces.after = ''
|
||||
return false
|
||||
}
|
||||
// /deep/ alias for >>>, since >>> doesn't work in SASS
|
||||
if (n.type === 'tag' && n.value === '/deep/') {
|
||||
const prev = n.prev()
|
||||
if (prev && prev.type === 'combinator' && prev.value === ' ') {
|
||||
prev.remove()
|
||||
}
|
||||
n.remove()
|
||||
return false
|
||||
}
|
||||
if (n.type !== 'pseudo' && n.type !== 'combinator') {
|
||||
node = n
|
||||
}
|
||||
})
|
||||
selector.insertAfter(node, selectorParser.attribute({
|
||||
attribute: id
|
||||
}))
|
||||
})
|
||||
}).process(node.selector).result
|
||||
})
|
||||
|
||||
// If keyframes are found in this <style>, find and rewrite animation names
|
||||
// in declarations.
|
||||
// Caveat: this only works for keyframes and animation rules in the same
|
||||
// <style> element.
|
||||
if (Object.keys(keyframes).length) {
|
||||
root.walkDecls(decl => {
|
||||
// individual animation-name declaration
|
||||
if (/-?animation-name$/.test(decl.prop)) {
|
||||
decl.value = decl.value.split(',')
|
||||
.map(v => keyframes[v.trim()] || v.trim())
|
||||
.join(',')
|
||||
}
|
||||
// shorthand
|
||||
if (/-?animation$/.test(decl.prop)) {
|
||||
decl.value = decl.value.split(',')
|
||||
.map(v => {
|
||||
const vals = v.trim().split(/\s+/)
|
||||
const i = vals.findIndex(val => keyframes[val])
|
||||
if (i !== -1) {
|
||||
vals.splice(i, 1, keyframes[vals[i]])
|
||||
return vals.join(' ')
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
})
|
||||
.join(',')
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
const postcss = require('postcss')
|
||||
|
||||
module.exports = postcss.plugin('trim', opts => css => {
|
||||
css.walk(({ type, raws }) => {
|
||||
if (type === 'rule' || type === 'atrule') {
|
||||
raws.before = raws.after = '\n'
|
||||
}
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user