Page MenuHomePhabricator

[EPIC] Set up a new shared Vue component library
Open, HighPublic

Description

As a result of decisions made at the recent Vue.js Developer Summit, a new library will serve as the canonical, shared Vue.js user-interface component library as future development standard in MediaWiki. This library will be collaboratively built by the Wikimedia Foundation, Wikimedia Deutschland, and volunteer developers.

The ultimate goal of this task is to enable code contributions to the library.

Order of operations

1. Create a new repository for the shared library

To do:

  • Create a subtask for this (@Catrope)
  • Create the new repository in Gerrit. (Eventually, we may consider moving to GitLab.)
  • Document it on Phabricator by creating a new tag or workboard for the library
2. Set up tooling

The following items require setup and configuration (and npm scripts, if applicable):

  • Linters and code formatters
  • Vite
  • Vue 3.x and the first Vue component (Button)
  • CSS tooling and define guidelines for authoring styles
  • TypeScript
  • Jest
  • Docker configuration for local development and production releases (or maybe we should just add a task for this and do it later so it doesn't block this epic)
  • git hooks
  • More?
3a. Create a stable design token setup

To do:

  • Create a subtask for this once the details – T288383 – are finalized (@Volker_E)
  • Set up and document design token architecture and standards. This should be finalized and stable to enable easier contributions.

Note that documenting design tokens on the demo site could be completed as part of step 4, or separately from this epic at a later date.

3b. Set up docs site and basic documentation structure

To do:

  • Create a subtask for this once T290912 is resolved (@AnneT)
  • Set up basic functionality of the demo tool
  • Set up basic documentation structure: introduction, for developers, contributing, etc.
  • Document the Button component as an example
4a. Document basic usage and developer guidelines

To do:

  • Add basic usage info to the README in the repository root, and to the docs intro page
  • Add developer docs covering
4b. Document contribution guidelines and guiding principles

To do:

  • Add contributing guidelines to the library (see T291417)
  • Add library guiding principle to the library (see T288380)
  • Make them visible in the demo site
5. Determine contribution process for existing library code

To do:

  • Agree with key library stakeholders how we will add and review code from existing libraries (e.g. WVUI and WiKit) (see T291416)

Definition of Done

  • New repository is created in Gerrit for the library
  • Associated Phab artifacts are created
  • Vue 3, Vite, TypeScript, Jest, linters, and all other tooling described in part 4 of this list are installed and configured
  • CSS pre- or postprocessor is implemented
  • Demo tool is installed and configured for development and documentation
  • README.md, contributing guidelines CONTRIBUTING.md, and developer guidelines DEVELOPERS.md are written and visible in the demo tool
  • Design token architecture is determined and anything related is configured in the library
  • We have a plan for adding existing components to the new library

Related Objects

Event Timeline

This looks great! The only other thing I can think of is:

When I set up a new repo for an experiment our team was doing back in February/March, I found it very helpful to have at least one component to start with. It was much easier to do that than to try to set up an empty library that's just scaffolding, because then there's nothing to test with. I ended up starting with a copy of the WVUI button component, because it's relatively simple and doesn't have any dependencies (it doesn't use any other components and doesn't use the icon system).

@Sarai-WMDE Would you share the comparison between the existing contribution guidelines of WVUI and Wikit that you've prepared and we've discussed in Berlin?

When we create this new repo, I'd like to recommend that we use Vite's "library mode" feature to build the bundles for distribution.

I've been using this in a small demo repo I set up recently to test out some of the new tools we are looking at.

Library mode gives us an easy way to build multiple bundles in different formats (UMD, ESM, CJS, etc) without including stuff we don't want (like the index.html demo page). By configuring some Rollup options (Vite uses Rollup for builds), you can split out all CSS from all components into a single file, externalize peer dependencies like vue itself, and do many other sorts of optimizations.

Fortunately Vite does most of what we want automatically so config is minimal. Here's how I set up the "library build" of my demo Tabs components:

vite.config.js
import { defineConfig } from 'vite'
import path from 'path';
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
	build: {
		target: 'es2015',
		minify: true,
		emptyOutDir: true,

		lib: {
			name: 'VueTabs',
			entry: path.resolve( __dirname, 'src/lib.js' ),
			formats: [ 'esm', 'cjs' ]
		},

		rollupOptions: {
			output: {
				entryFileNames: 'vue-tabs.[format].js',
				assetFileNames: 'vue-tabs.[name].[ext]'
			},

			external: [ 'vue' ]
		}
	},

	plugins: [ vue() ]
} );

This produces the following:

dist/
├── vue-tabs.cjs.js
├── vue-tabs.es.js
└── vue-tabs.style.css
  • Tree-shaking happens by default (any unused code will be eliminated from build)
  • Vue component templates are compiled into render functions
  • CSS is compiled into a separate stand-alone file that only includes component style rules and inlined variables that were used (see CSS next config for details)
  • Vue.js itself has been externalized and will not be included in the build.
Volker_E renamed this task from [Epic] Set up a new shared Vue component library to [EPIC] Set up a new shared Vue component library.Sep 13 2021, 7:47 PM
Volker_E triaged this task as High priority.

@Sarai-WMDE Would you share the comparison between the existing contribution guidelines of WVUI and Wikit that you've prepared and we've discussed in Berlin?

Hi! I have to clarify that this is a misunderstanding. The consolidation work that I did was focused on our component design processes, not the contribution guidelines.

We'll for sure be taking a look at the information shared in this ticket and the WVUI documentation in preparation for the Task Force's Decisions Week.

From our side, all contribution guidelines are available in WiKit's Storybook and our repository docs.

I've updated this task to create an order of operations for practically splitting up the work to create the new library.

Items with the same number (e.g. 3a and 3b) can be done at the same time. Otherwise, the steps must happen in order. Please let me know if you have suggestions to optimize this process.

@egardner and @Catrope especially, please take a look at step 2 and see if you can reorder or split up those tasks in a way that makes it easier to distribute. I'm not exactly sure which of those items you'll want to do altogether, and which can be split up. Let's think about this and document it before the task force.

I've also made documenting design tokens on the demo site out of scope here. I think it's something we should create a task for and do ASAP, but I figured it could happen immediately after these others items if need be. @Volker_E or @Sarai-WMDE especially, please let me know if you disagree and we can add it here.

AnneT updated the task description. (Show Details)

@AnneT this is great, thanks for updating & clarifying here.

Docker configuration for local development and production releases (or maybe we should just add a task for this and do it later so it doesn't block this epic)

Big +1 to this

Vue 3.x and the first Vue component (Button)

This gets to something we haven't discussed much so far – when/where do we want use Vue 3's composition API (as opposed to the traditional options API) when introducing new components? Do we want to encourage the use of one or the other (or discourage using both APIs in the same file) when all other things are equal? The same goes for the use of the <script setup> pattern for SFCs. I don't think this deserves its own subtask (it's not an either-or / irrevocable decision like some others are), but perhaps this should be part of the discussion around contribution guidelines & design principles.

These are excellent questions, @egardner, thanks for bringing them up.

FWIW, in WVUI we've been sort of progressively introducing the composition API into components when it makes sense to do so, because we started with Vue 2 and are all used to the options API. Consider the case of Button: this component is simple and doesn't implement any shared code, so using the options API makes sense: everything is clear thanks to the consistent organization of items in the options API. However, what if we want to abstract out some functionality in the future to be shared with another similar component via a composable? We'd want to refactor the file to use the setup option at least for that shared thing. Do we move everything into setup? Or just that shared thing?

My priorities are to make code organization at least somewhat predictable, to make sure files are readable, and to make maintenance easier. I'd love to hear from @Jakob_WMDE, @Tonina_Zhelyazkova_WMDE, and @Lindsaykwardell in particular, if you have any thoughts about what we might standardize on!

Consider the case of Button: this component is simple and doesn't implement any shared code, so using the options API makes sense: everything is clear thanks to the consistent organization of items in the options API.

It's true that the extra "boilerplate" of the options API provides a consistent structure and makes it easier to know where to look for things; if we use <script setup> it's more on us to ensure some consistency across components (part of why we should think about this early on I'd say).

Our decision around Typescript could also play a big role here; the composition API and <script setup> syntax provide a lot of Typescript-specific amenities, and this approach might allow us to write cleaner/more legible code if we decide to go "all in" on TS.

Evan You's position is that <script setup> and Composition API is the recommended pattern going forward, and that the Vue documentation will be updated to reflect that. Source: https://github.com/vuejs/rfcs/discussions/378#discussioncomment-1158805

Yes, the docs are a bit outdated in this regard. The current recommended approach is:
Use SFC + <script setup> + Composition API
Use VSCode + Volar (or WebStorm once its support for <script setup> ships soon)
Not strictly required for TS, but if applicable, use Vite for build tooling.

That said, the Options API is still a valid way to build components, and I feel it's all right if the WMF adopts that as its default way to write Vue SFC's.

Evan You's position is that <script setup> and Composition API is the recommended pattern going forward, and that the Vue documentation will be updated to reflect that. Source: https://github.com/vuejs/rfcs/discussions/378#discussioncomment-1158805

Interesting, I was leaning away from <script setup> because it seemed like it would be harder to standardize on some coding patterns, but if it's meant to be the new standard that's a very compelling argument in favor of it. We definitely want to stick to doing things the "Vue way" as much as possible. To echo Eric, we should consider how we can add some consistency between components within <script setup>.