From 96c72ff90e91dbbdba2e587c33fd0cc5b3ad2d32 Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 29 Jun 2020 15:57:59 -0400 Subject: [PATCH 01/14] sfc improvements --- active-rfcs/0000-sfc-component-sugar.md | 128 +++++++++++ active-rfcs/0000-sfc-script-setup.md | 278 ++++++++++++++++++++++++ active-rfcs/0000-sfc-style-variables.md | 82 +++++++ 3 files changed, 488 insertions(+) create mode 100644 active-rfcs/0000-sfc-component-sugar.md create mode 100644 active-rfcs/0000-sfc-script-setup.md create mode 100644 active-rfcs/0000-sfc-style-variables.md diff --git a/active-rfcs/0000-sfc-component-sugar.md b/active-rfcs/0000-sfc-component-sugar.md new file mode 100644 index 00000000..ebafc46b --- /dev/null +++ b/active-rfcs/0000-sfc-component-sugar.md @@ -0,0 +1,128 @@ +- Start Date: 2020-06-29 +- Target Major Version: 2.x & 3.x +- Reference Issues: N/A +- Implementation PR: N/A + +# Summary + +Syntax sugar for reducing component import and registration boilerplate in Single File Components. + +# Basic example + +```html + + + +``` + +# Motivation + +Currently in SFCs you have to import a component and then pass it to the `export default { components: { ... } }` hash, which leads to a lot of redundancy: for a single component we are repeating its name 3 times: in the imported binding, the file name, and the components option. + +The `` sugar requires the name of each component to be specified only once. + +# Detailed design + +## Normal Components + +**Before** + +```html + + + +``` + +**After** + +```html + + + +``` + +## Async Components + +**Before** + +```html + + + +``` + +**After** + +```html + + + +``` + +## Component Renaming + +By default, the component's locally registered name is inferred from its filename. But they can be renamed locally: + +```html + + + +``` + +# Drawbacks + +This would require updates in tools that parse SFC content for template analysis - e.g. Vetur & `@vuedx`. + +However, since this information is going to be provided directly by `@vue/compiler-sfc` in the parsed SFC descriptor, it should remove some extra complexity from these tools as well. + +# Alternatives + +We considered implicitly registering imported components: + +```html + + + +``` + +However, this approach has a few issues: + +- `Foo` is unused in the script scope, making it annoying when using linter rules that check for unused variables. + +- The only safe assumption about an import being a Vue component is the `.vue` extension, which makes it unable to support components authored in non-SFC formats (e.g. `import Foo from './Foo/ts'` can be a component but we can't really be sure). + +# Adoption strategy + +This is a fully backwards compatible new feature. However, we probably want to warn users against mixing the manual imports and `` tags so that tools that rely on the extracted information can make safer assumptions. diff --git a/active-rfcs/0000-sfc-script-setup.md b/active-rfcs/0000-sfc-script-setup.md new file mode 100644 index 00000000..5f4acd01 --- /dev/null +++ b/active-rfcs/0000-sfc-script-setup.md @@ -0,0 +1,278 @@ +- Start Date: 2020-06-29 +- Target Major Version: 2.x & 3.x +- Reference Issues: N/A +- Implementation PR: N/A + +# Summary + +Introduce a compile step for ` +``` + +# Motivation + +When authoring components using the Composition API, very often `setup` is the only option that's being used. This results in some unnecessary boilerplate: + +```js +import { ref } from 'vue' + +export default { + setup() { + const count = ref(0) + const inc = () => count.value++ + + return { + count, + inc + } + } +} +``` + +In addition, one of the most often complained about aspect of the Composition API is the necessity to repeat all the bindings that need to be exposed to the render context using a return object. + +This RFC introduces a compiler-powered alternative for the usage of ` +``` + +This will compile to: + +```js +import { computed } from 'vue' + +const $options = { + props: { + msg: String + }, + inheritAttrs: false +} + +export default { + ...$options, + setup($props) { + const computedMsg = computed(() => $props.msg + '!!!') + + return { + computedMsg + } + } +} +``` + +## With TypeScript + +` +``` + +The above will compile to: + +```vue + +``` + +- Runtime props declaration is automatically generated from TS typing to remove the need of double declaration and still ensure correct runtime behavior. (It is force casted into `undefined` to ensure the user provided type is used in the emitted code) + +- The emitted code is still TypeScript with valid typing, which can be further processed by other tools. + +# Drawbacks + +This is yet another way of authoring components, and it requires understanding the Composition API first. + +# Adoption strategy + +This is a fully backwards compatible new feature. + + +# Unresolved Questions + +## Magic `let` bindings + +It is technically possible to compile `let` bindings in a way so that root level `let` bindings are implicitly reactive: + +```vue + +``` + +can be compiled into: + +```vue + +``` + +This makes the code even more succinct and removes the need to use `ref` in the root scope of the component. However, this may be a bit too magical and there are a number of consistency issues if we enable this behavior: + +- Objects are not implicitly reactive: + + ```js + export const state = { count: 0 } + + export function increment() { + // doesn't work + state.count++ + } + ``` + + Making root scope objects deeply reactive by default can lead to potential performance problems, since the user may declare a 3rd party object of unknown size. + +- Doesn't work inside nested functions: + + ```js + function useFeature() { + // not reactive, since it's not root level + let count = 1 + const inc = () => count++ + + return { + count, + inc + } + } + ``` + + If we also compile functions inside ` + + +``` + +# Motivation + +Vue SFC styles provide straightforward CSS collocation and encapsulation, but it is purely static - which means up to this point we have no capability of dynamically updating the styles at runtime based on the component's state. + +Now with [most modern browsers supporting native CSS variables](https://caniuse.com/#feat=css-variables), we can leverage it to easily connect the component's state and styles. + +# Detailed design + +The ` +``` + +However, this has a few disadvantages: + +- Intention is less explicit; + +- Requires a full PostCSS parse first to extract matching variables before the main script can be processed. With `:vars` being declared on the ` +``` + +The inner CSS will be compiled into: -## Auto Detect Variables +```css +h1 { + color: var(--6b53742-color); +} +``` -One of the considered alternatives is auto detecting variables to inject using a naming convention: +**Note that when `scoped` and `vars` are both present, all CSS variables are considered to be local.** In order to reference a global CSS variable here, use the `global:` prefix: ```html - ``` -However, this has a few disadvantages: +The above compiles into: -- Intention is less explicit; +```css +h1 { + color: var(--6b53742-color); + font-size: var(--fontSize); +} +``` -- Requires a full PostCSS parse first to extract matching variables before the main script can be processed. With `:vars` being declared on the `