logologo

Notes

Quick notes / tips

RSS Feed

Typed provide and inject in Vue

2021/03/05

I didn’t know that you can type provide() and inject() elegantly until I watched Thorsten Lünborg’s talk on Vue Amsterdam.

The basic idea here is the Vue offers a type utility InjectionKey will you can type a Symbol to hold the type of your injection values. And when you use provide() and inject() with that symbol, it can infer the type of provider and return value automatically.

For example:

// context.ts
import { InjectionKey } from 'vue'

export interface UserInfo {
  id: number
  name: string
}

export const InjectKeyUser: InjectionKey<UserInfo> = Symbol()
// parent.vue
import { provide } from 'vue' 
import { InjectKeyUser } from './context'

export default {
  setup() {
    provide(InjectKeyUser, {
      id: '117', // type error: should be number
      name: 'Anthony'
    })
  }
}
// child.vue
import { inject } from 'vue' 
import { InjectKeyUser } from './context'

export default {
  setup() {
    const user = inject(InjectKeyUser) // UserInfo | undefined

    if (user) {
      console.log(user.name) // Anthony
    }
  }
}

See the docs for more details.

Color Scheme for VS Code Extensions

2021/03/01

There is currently no API to access colors of current theme in VS Code Extensions, nor the meta information of them. It frustrated me for a long while, until today I came up with a dirty but working solution.

Since most of the themes follow the conversions of having Light or Dark in their names. Then we can have:

import { workspace } from 'vscode'

export function isDarkTheme() {
  const theme = workspace.getConfiguration()
    .get('workbench.colorTheme', '')

  // must be dark
  if (theme.match(/dark|black/i) != null)
    return true

  // must be light
  if (theme.match(/light/i) != null)
    return false

  // IDK, maybe dark
  return true
}

Simple, but surprisingly, it works really well. This is used for my Browse Lite extension to inject the preferred color schema matching with VS Code’s theme. And also Iconify IntelliSense for VS Code to update icons color with the theme.

Type Your Config

2021/02/29

Configurations can be quite complex, and sometimes you may want to utilize the great type checking that TypeScript provided. Change your xxx.config.js to xxx.config.ts is not an ideal solutions as you will need to have a Node.js register involved to transpile it into JavaScript and some tools might not support doing that way. Fortunately, TypeScript also support type check in plain JavaScript file with JSDoc. Here is an example of Webpack config with type checks:

// webpack.config.js
// @ts-check

/**
 * @type {import('webpack').Configuration}
 */
const config = {
  /*...*/
}

module.exports = config

Prefect. Everything should work and you can already call it a day.

I have never thought about we can do better, until I saw Vite’s approach. In Vite, you can simply have:

// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  /*...*/
})

No JSDocs, no need to declare a variable first then export it. And since TypeScript will infer the types even you are using plain JavaScript, it works great with both.

How? The defineConfig is literally a pass-through, but brings with types:

import { UserConfig } from 'vite'

export function defineConfig(options: UserConfig) {
  return options
}

defineConfig exists in the runtime, so it works for JavaScript even if the types get truncated. This is really just some small details of DX, but I would wish more tools could adapt this approach and make the type checking more approachable and simpler.

Match Quotes in Pairs

2021/02/28

In JavaScript, single quotes('') and double quotes("") are interchangeable. With ES6, we now even have backticks(``) for template literals. When you want to write a quick script to find all the strings without introducing a heavy parser, you may think about using RegExp. For example, you can have:

/['"`](.*?)['"`]/gm

It works for most of the case, but not for mixed quotes:

`const a = "Hi, I'm Anthony"`.match(/['"`](.*)['"`]/m)[1] // "Hi, I"

You have to make sure the starting quote and ending quote are the same type. Initially I thought it was impossible to do it in RegExp, or we have to do like this:

/'(.*?)'|"(.*?)"|`(.*?)`/gm

That’s definitely a bad idea as it makes you duplicated your notations. Until I found this solution:

/(['"`])(.*?)\1/gm

\1 is a Backreferences to your first group, similarly you can have \2 for the second group 2 and \3 for the third, you got the idea. This is exactly what I need! Take it a bit further, to exclude the backslash escaping, now we can have a much reliable RegExp for extracting quoted texts from any code.

/(["'`])((?:\\\1|(?:(?!\1)|\n|\r).)*?)\1/mg

You can find it running in action on my vite-plugin-windicss.

Match Chinese Characters

2021/02/25

When you need to detect if a string contains Chinese characters, you would commonly think about doing it will RegExp, or grab a ready-to-use package on npm.

If you Google it, you are likely end up with this solution:

/[\u4E00-\u9FCC\u3400-\u4DB5\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\ud840-\ud868][\udc00-\udfff]|\ud869[\udc00-\uded6\udf00-\udfff]|[\ud86a-\ud86c][\udc00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d]/

It works, but a bit dirty. Fortunately, I found a much simpler solution today:

/\p{Script=Han}/u
!!'你好'.match(/\p{Script=Han}/u) // true

It’s called Unicode property escapes and already available in Chrome 64, Firefox 79, Safari 11.1 and Node.js 10.

All available scripts here.

Netlify Redirects (Domains)

2021/02/20

On Netlify, you can setup multiple domains for a site. When you add a custom domain, the xxx.netlify.app is still accessible. Which would potentially cause some confusion to users. In that way, you can setup the redirection in your netlify.toml file, for example:

[[redirects]]
  from = "https://vueuse.netlify.app/*"
  to = "https://vueuse.org/:splat"
  status = 301
  force = true
  • * and :splat mean it will redirect all the sub routes as-is to the new domain.
  • force = true specifying it will always redirect even if the request page exists.

Netlify Redirects (Site names)

2021/02/20

Unlike domain redirection, sometimes you would need to rename the Netlify subdomain name (a.k.a site name), for example xxx.netlify.app to yyy.netlify.app. After you do the rename, people visiting xxx.netlify.app will receive a 404. And since you no longer have controls over xxx.netlify.app, you can’t just setup a redirect in your new site.

A solution here is to create a new site with your original name xxx and upload the redirection rules. In this case, we can have netlify.toml like this:

[[redirects]]
  from = "*"
  to = "https://yyy.netlify.app/:splat"
  status = 301
  force = true

Note you don’t have to link a repo to that, Netlify offers a great feature that let you drag and drop for static files and serve as a site. So you can just save netlify.toml and upload it, rename the site to your original name. The redirection is done!

CC BY-NC-SA 4.0 2021 © Anthony Fu