From 66503ca6780ba2c0855915030372a0bd58bf52ce Mon Sep 17 00:00:00 2001
From: EGOIST <0x142857@gmail.com>
Date: Sat, 18 Jan 2020 17:03:50 +0800
Subject: [PATCH 1/3] chore: add note for using global style
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 30a257e..08e8d23 100644
--- a/README.md
+++ b/README.md
@@ -204,13 +204,15 @@ import { css } from 'styled-vue'
export default {
globalStyle: css`
- body {
+ #app {
color: ${vm => vm.bodyColor};
}
`
}
```
+Note CSS variables can only apply to current component and child components, so if you are trying to use them on parent selector like `body`, they **WON'T** work! Currently there's no easy way to fix this.
+
### TypeScript
We use Babel to parse your code, so TypeScript should work out-of-the-box, however there're some [caveats](https://babeljs.io/docs/en/babel-plugin-transform-typescript#caveats).
From af2e8f765a13991a8a33b2aa78a0c00a9e34c662 Mon Sep 17 00:00:00 2001
From: EGOIST <0x142857@gmail.com>
Date: Sat, 18 Jan 2020 17:05:01 +0800
Subject: [PATCH 2/3] chore: tweaks
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 08e8d23..9435fc9 100644
--- a/README.md
+++ b/README.md
@@ -211,7 +211,7 @@ export default {
}
```
-Note CSS variables can only apply to current component and child components, so if you are trying to use them on parent selector like `body`, they **WON'T** work! Currently there's no easy way to fix this.
+Note CSS variables (dynamic value) can only apply to current component and child components, so if you are trying to use them on parent selector like `body`, they **WON'T** work! Currently there's no easy way to fix this.
### TypeScript
From 63d54978d2600dc404ac3da8e797baf459bd5897 Mon Sep 17 00:00:00 2001
From: EGOIST <0x142857@gmail.com>
Date: Sat, 18 Jan 2020 18:18:14 +0800
Subject: [PATCH 3/3] feat: improve global style support
---
README.md | 24 +++++-
example/App.vue | 2 +-
example/index.js | 3 +
example/poi.config.js | 2 +
lib/index.js | 27 ++++++-
lib/parseComponent.js | 21 ++++--
lib/parseScript.js | 74 +++++++------------
.../__snapshots__/parseComponent.test.js.snap | 22 ++----
8 files changed, 102 insertions(+), 73 deletions(-)
diff --git a/README.md b/README.md
index 9435fc9..dbd62ab 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,17 @@
yarn add styled-vue --dev
```
+Then register the Vue plugin (**optional**):
+
+```js
+import Vue from 'vue'
+import { StyledVue } from 'styled-vue'
+
+Vue.use(StyledVue)
+```
+
+So far the plugin is only required for [globalStyle](#globalstyle), if you only need scoped style, you can safely skip this.
+
## Example
```vue
@@ -204,14 +215,23 @@ import { css } from 'styled-vue'
export default {
globalStyle: css`
- #app {
+ body {
color: ${vm => vm.bodyColor};
}
`
}
```
-Note CSS variables (dynamic value) can only apply to current component and child components, so if you are trying to use them on parent selector like `body`, they **WON'T** work! Currently there's no easy way to fix this.
+`globalStyle` relies on the Vue plugin, make sure the register it first:
+
+```js
+import Vue from 'vue'
+import { StyledVue } from 'styled-vue'
+
+Vue.use(StyledVue)
+```
+
+This only adds ~100 bytes to your application.
### TypeScript
diff --git a/example/App.vue b/example/App.vue
index 65c2c42..0b070fc 100644
--- a/example/App.vue
+++ b/example/App.vue
@@ -16,7 +16,7 @@ const border = `10px solid pink`
export default {
globalStyle: css`
- #app {
+ body {
border: ${border};
}
`,
diff --git a/example/index.js b/example/index.js
index 385fcfe..aab98c7 100644
--- a/example/index.js
+++ b/example/index.js
@@ -1,6 +1,9 @@
import Vue from 'vue'
+import { StyledVue } from 'styled-vue'
import App from './App.vue'
+Vue.use(StyledVue)
+
new Vue({
el: '#app',
render: h => h(App)
diff --git a/example/poi.config.js b/example/poi.config.js
index 75c3bd7..00e1245 100644
--- a/example/poi.config.js
+++ b/example/poi.config.js
@@ -10,5 +10,7 @@ module.exports = {
options.compiler = require('../compiler')
return options
})
+
+ config.resolve.alias.set('styled-vue', path.join(__dirname, '../lib'))
}
}
diff --git a/lib/index.js b/lib/index.js
index ccae2e7..c93fd28 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,2 +1,25 @@
-// noop
-export const css = () => ''
+Object.defineProperty(exports, '__esModule', { value: true })
+
+function css(_) {
+ throw new Error(
+ `You need to replace vue-template-compiler with styled-vue/compiler`
+ )
+}
+
+function StyledVue(Vue) {
+ Vue.component('styled-vue-global-css', {
+ render(h) {
+ const globalStyle = this.$parent.$options.globalStyle(this.$parent)
+ let css = ''
+ // eslint-disable-next-line guard-for-in
+ for (const key in globalStyle) {
+ css += key + ':' + globalStyle[key] + ';'
+ }
+ return h('style', {}, [':root {' + css + '}'])
+ }
+ })
+}
+
+exports.css = css
+
+exports.StyledVue = StyledVue
diff --git a/lib/parseComponent.js b/lib/parseComponent.js
index 996f7d6..7bff065 100644
--- a/lib/parseComponent.js
+++ b/lib/parseComponent.js
@@ -11,23 +11,30 @@ module.exports = (content, opts) => {
styleLang,
hasVars,
scriptContent,
+ hasGlobalVars,
globalStyle,
globalStyleLang
} = parseScript(sfc.script)
sfc.script.content = scriptContent
- if (sfc.template && hasVars) {
+ if (sfc.template && (hasVars || hasGlobalVars)) {
sfc.template.content = posthtml([
tree => {
for (const node of tree) {
if (node.tag) {
- node.attrs = node.attrs || {}
- const existing =
- node.attrs[':style'] || node.attrs['v-bind:style']
- node.attrs[
- ':style'
- ] = `$options._getCssVariables(this, $options, ${existing})`
+ if (hasVars) {
+ node.attrs = node.attrs || {}
+ const existing =
+ node.attrs[':style'] || node.attrs['v-bind:style']
+ node.attrs[':style'] = `$options.style(this, ${existing})`
+ }
+ if (node.content && hasGlobalVars) {
+ node.content.unshift({
+ tag: 'styled-vue-global-css'
+ })
+ }
+ break
}
}
return tree
diff --git a/lib/parseScript.js b/lib/parseScript.js
index 1e8293a..79599f1 100644
--- a/lib/parseScript.js
+++ b/lib/parseScript.js
@@ -9,9 +9,10 @@ const LANGS = ['css', 'stylus', 'less', 'sass', 'scss']
module.exports = script => {
let style
let styleLang
- let hasVars = false
let globalStyle
let globalStyleLang
+ let hasVars = false
+ let hasGlobalVars = false
const ast = parser.parse(script.content, {
sourceType: 'module',
@@ -40,7 +41,6 @@ module.exports = script => {
type: 'TemplateElement',
value: { raw: value, cooked: value }
})
- hasVars = true
// Check unit
let unit
@@ -140,14 +140,14 @@ module.exports = script => {
continue
}
- styleLang = specifier.imported.name
+ const lang = specifier.imported.name
- if (!LANGS.includes(styleLang)) {
- throw new Error(`[styled-vue] "${styleLang}" is not supported`)
+ if (!LANGS.includes(lang)) {
+ throw new Error(`[styled-vue] "${lang}" is not supported`)
}
const binding = path.scope.getBinding(specifier.local.name)
- let objectExpressionPath
+
for (let i = 0; i < binding.referencePaths.length; i++) {
// The tagged template path
const ref = binding.referencePaths[i].parentPath
@@ -164,9 +164,6 @@ module.exports = script => {
)
}
- // The object expression path
- objectExpressionPath = propertyPath.parentPath
-
const isGlobal = propertyPath.node.key.name === 'globalStyle'
const { vars, varDeclarations, extractedStyle } = parseTaggedTemplate(
ref,
@@ -174,18 +171,36 @@ module.exports = script => {
)
if (isGlobal) {
globalStyle = extractedStyle
+ globalStyleLang = lang
+ if (vars.length > 0) {
+ hasGlobalVars = true
+ }
} else {
style = extractedStyle
+ styleLang = lang
+ if (vars.length > 0) {
+ hasVars = true
+ }
}
if (vars.length > 0) {
ref.replaceWith(
t.functionExpression(
null,
- [t.identifier('vm'), t.identifier('existing')],
+ [
+ t.identifier('vm'),
+ !isGlobal && t.identifier('existing') // Global vars are handled differently
+ ].filter(Boolean),
t.blockStatement([
...varDeclarations,
- t.returnStatement(t.objectExpression(vars))
+ t.returnStatement(
+ isGlobal
+ ? t.objectExpression(vars)
+ : t.arrayExpression([
+ t.identifier('existing'),
+ t.objectExpression(vars)
+ ])
+ )
])
)
)
@@ -197,42 +212,6 @@ module.exports = script => {
ref.replaceWith(NoVarsFound)
}
}
-
- if (hasVars && objectExpressionPath) {
- const createObjectCall = name => {
- return t.logicalExpression(
- '&&',
- t.memberExpression(t.identifier('options'), t.identifier(name)),
- t.callExpression(
- t.memberExpression(t.identifier('options'), t.identifier(name)),
- [t.identifier('vm')]
- )
- )
- }
-
- objectExpressionPath.node.properties.push(
- t.objectProperty(
- t.identifier('_getCssVariables'),
- t.functionExpression(
- null,
- [
- t.identifier('vm'),
- t.identifier('options'),
- t.identifier('existing')
- ],
- t.blockStatement([
- t.returnStatement(
- t.arrayExpression([
- t.identifier('existing'),
- createObjectCall('globalStyle'),
- createObjectCall('style')
- ])
- )
- ])
- )
- )
- )
- }
}
// Remove the import
@@ -245,6 +224,7 @@ module.exports = script => {
styleLang,
globalStyle,
globalStyleLang,
+ hasGlobalVars,
hasVars,
scriptContent: generator.default(ast).code
}
diff --git a/test/__snapshots__/parseComponent.test.js.snap b/test/__snapshots__/parseComponent.test.js.snap
index cb163c6..179d5f2 100644
--- a/test/__snapshots__/parseComponent.test.js.snap
+++ b/test/__snapshots__/parseComponent.test.js.snap
@@ -31,7 +31,7 @@ export default {
-
@@ -73,7 +73,7 @@ export default {
-
@@ -106,7 +106,7 @@ export default {
-hello
+hello
@@ -114,21 +114,18 @@ export default {
export default {
style: undefined // No CSS variables
,
- globalStyle: function (vm, existing) {
+ globalStyle: function (vm) {
var gv0 = vm => vm.fontSize;
return {
\\"--gv0\\": gv0(vm)
};
- },
- _getCssVariables: function (vm, options, existing) {
- return [existing, options.globalStyle && options.globalStyle(vm), options.style && options.style(vm)];
}
};
-
@@ -233,7 +230,7 @@ exports[`simple 1`] = `
-hello
+hello
@@ -243,13 +240,10 @@ exports[`simple 1`] = `
var v0 = vm => vm.color;
var v1 = 200 + 1;
- return {
+ return [existing, {
\\"--v0\\": v0(vm),
\\"--v1\\": v1 + \\"px\\"
- };
- },
- _getCssVariables: function (vm, options, existing) {
- return [existing, options.globalStyle && options.globalStyle(vm), options.style && options.style(vm)];
+ }];
}
};