Skip to content

Instantly share code, notes, and snippets.

View johnsoncodehk's full-sized avatar

Johnson Chu johnsoncodehk

View GitHub Profile
del /s /q /f /a .DS_STORE
del /s /q /f /a ._*
del /s /q /f /a *DS_STORE
pause
@johnsoncodehk
johnsoncodehk / Unity.gitignore
Created December 1, 2018 21:09
.gitignore for Unity
/*
/*/
!/Assets/
!/Packages/
!/ProjectSettings/
!.gitignore
@johnsoncodehk
johnsoncodehk / trim-trailing-slash.js
Last active January 29, 2026 09:36
Remove URL trailing slash
window.history.replaceState("", "", window.location.href.replace(new RegExp("/(?!.*/)"), ""))
@johnsoncodehk
johnsoncodehk / cheapComputed.ts
Last active August 27, 2020 23:16
Vue 3 "cheap" computed
import { computed, ref } from "vue";
import { ComputedGetter, pauseTracking, resetTracking } from "@vue/reactivity";
// if no version, not work for objects/arrays...
export function cheapComputed<T, K = T>(getValue: ComputedGetter<T>, getVersion?: ComputedGetter<K>) {
const value = computed(getValue);
const version = getVersion ? computed(getVersion) : value;
const lastValue = ref<T>();
const lastVersion = ref<K>();
const changed = computed(() => version.value !== lastVersion.value);
/**
*
* @type {import('@tsslint/config').Rule}
*/
const noConsoleRule = ({ typescript: ts, sourceFile, reportWarning }) => {
ts.forEachChild(sourceFile, function walk(node) {
if (
ts.isPropertyAccessExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === 'console'
import type { Rule } from '@tsslint/config';
export function create(): Rule {
return ({ typescript: ts, sourceFile, languageService, reportWarning }) => {
ts.forEachChild(sourceFile, function walk(node) {
if (ts.isNonNullExpression(node)) {
const typeChecker = languageService.getProgram()!.getTypeChecker();
const type = typeChecker.getTypeAtLocation(node.expression);
if (
typeChecker.typeToString(type, undefined, ts.TypeFormatFlags.NoTruncation)
import type { Rule } from '@tsslint/config';
export function create(): Rule {
return ({ typescript: ts, sourceFile, reportWarning }) => {
ts.forEachChild(sourceFile, function cb(node) {
if (
ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === 'alert'
) {
import type { SFCParseResult, VueLanguagePlugin } from '../types';
import { parse } from '../utils/parseSfc';
const jsxWrapper = ['<script setup lang="jsx">\n', '\n</script>'];
const tsxWrapper = ['<script setup lang="tsx">\n', '\n</script>'];
const plugin: VueLanguagePlugin = _ctx => {
return {

Volar 2.0: The Rewrite

I'm Johnson, the author of Volar (now Vue Language Tools). We released 2.0 in March 2024. This is a look back at what we changed, why, and what it cost.

Why we needed to rewrite

Vetur and Volar v1 implemented Vue's IDE support through the Language Server Protocol. For small and medium projects this worked fine. For larger projects it broke down, and the reason was always the same: memory.

TypeScript Server and the Vue Language Server each kept their own copy of the project's TS AST — every file, every .d.ts in node_modules. When a project pulled in thousands of .d.ts files (common for anything with a big dependency tree), the two processes together could exhaust available memory.

import { createReactiveSystem, Dependency, Link, Subscriber, SubscriberFlags } from 'alien-signals/esm';
import { ReactiveFramework } from "../util/reactiveFramework";
let toCleanup: (() => void)[] = [];
export const alienSignalsStaticDeps: ReactiveFramework = {
type: "pure",
name: "alien-signals (static deps)",
signal: (initial) => {
const data = signal(initial);