Skip to content

Commit

Permalink
feat: use local ts instead of CDN, use vue worker for ts and js
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Dec 7, 2023
1 parent e9eb1ca commit dd23072
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 77 deletions.
47 changes: 19 additions & 28 deletions monaco/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,39 @@ import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'

// TODO: material-theme-palenight's format it not compatible with monaco
import themeDark from 'shikiji/themes/vitesse-dark.mjs'
import themeLight from 'shikiji/themes/vitesse-light.mjs'
import vueWorker from './vue.worker?worker'
import { loadWasm, reloadLanguageTools } from './env'
import type { Store, WorkerMessage } from './env'
import type { Store } from './env'

export function initMonaco(store: Store) {
self.MonacoEnvironment = {
async getWorker(_: any, label: string) {
if (label === 'vue') {
const worker = new vueWorker()
const init = new Promise<void>((resolve) => {
worker.addEventListener('message', (data) => {
if (data.data === 'inited')
resolve()
})
worker.postMessage({
event: 'init',
tsVersion: store.state.typescriptVersion,
tsLocale: undefined,
} satisfies WorkerMessage)
})
await init
return worker
}

if (label === 'json')
return new jsonWorker()
switch (label) {
case 'typescript':
case 'javascript':
case 'vue':
return new vueWorker()

if (label === 'css' || label === 'scss' || label === 'less')
return new cssWorker()
case 'json':
return new jsonWorker()

if (label === 'html' || label === 'handlebars' || label === 'razor')
return new htmlWorker()
case 'css':
case 'scss':
case 'less':
return new cssWorker()

if (label === 'typescript' || label === 'javascript')
return new tsWorker()
case 'html':
case 'handlebars':
case 'razor':
return new htmlWorker()

return new editorWorker()
default:
return new editorWorker()
}
},
}

Expand Down
57 changes: 8 additions & 49 deletions monaco/vue.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,36 @@ import {
createJsDelivrUriResolver,
decorateServiceEnvironment,
} from '@volar/cdn'
import * as ts from 'typescript'
import type { VueCompilerOptions } from '@vue/language-service'
import { resolveConfig } from '@vue/language-service'
import {
createLanguageHost,
createLanguageService,
createServiceEnvironment,
} from '@volar/monaco/worker'
import type { WorkerHost, WorkerMessage } from './env'
import type { WorkerHost } from './env'

export interface CreateData {
tsconfig: {
compilerOptions?: import('typescript').CompilerOptions
vueCompilerOptions?: Partial<VueCompilerOptions>
}
dependencies: Record<string, string>
}

let locale: string

let ts: typeof import('typescript')
let tsLocalized: any

globalThis.onmessage = async (msg: MessageEvent<WorkerMessage>) => {
if (msg.data?.event === 'init') {
if (msg.data.tsLocale)
locale = msg.data.tsLocale

;[ts, tsLocalized] = await Promise.all([
importTsFromCdn(msg.data.tsVersion),
locale
&& fetchJson(
`https://cdn.jsdelivr.net/npm/typescript@${msg.data.tsVersion}/lib/${locale}/diagnosticMessages.generated.json`,
),
])
globalThis.postMessage('inited')
return
}

globalThis.onmessage = async () => {
worker.initialize(
(
ctx: monaco.worker.IWorkerContext<WorkerHost>,
{ tsconfig, dependencies }: CreateData,
{ tsconfig }: CreateData,
) => {
const { options: compilerOptions } = ts.convertCompilerOptionsFromJson(
tsconfig?.compilerOptions || {},
'',
)

const env = createServiceEnvironment()
const host = createLanguageHost(
ctx.getMirrorModels,
Expand All @@ -63,22 +46,19 @@ globalThis.onmessage = async (msg: MessageEvent<WorkerMessage>) => {
const jsDelivrFs = createJsDelivrFs(ctx.host.onFetchCdnFile)
const jsDelivrUriResolver = createJsDelivrUriResolver(
'/node_modules',
dependencies,
{},
)

if (locale)
env.locale = locale

if (tsLocalized)
host.getLocalizedDiagnosticMessages = () => tsLocalized

decorateServiceEnvironment(env, jsDelivrUriResolver, jsDelivrFs)

return createLanguageService(
{ typescript: ts as any },
{ typescript: ts },
env,
resolveConfig(
ts as any,
ts,
{},
compilerOptions,
tsconfig.vueCompilerOptions || {},
Expand All @@ -88,24 +68,3 @@ globalThis.onmessage = async (msg: MessageEvent<WorkerMessage>) => {
},
)
}

async function importTsFromCdn(tsVersion: string) {
const _module = globalThis.module
;(globalThis as any).module = { exports: {} }
const tsUrl = `https://cdn.jsdelivr.net/npm/typescript@${tsVersion}/lib/typescript.js`
await import(/* @vite-ignore */ tsUrl)
const ts = globalThis.module.exports
globalThis.module = _module
return ts as typeof import('typescript')
}

async function fetchJson(url: string) {
try {
const res = await fetch(url)
if (res.status === 200)
return await res.json()
}
catch {
// ignore
}
}
1 change: 1 addition & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default defineNuxtConfig({
'@volar/cdn',
'@vue/language-service',
'@volar/monaco/worker',
'typescript',
],
},
},
Expand Down

0 comments on commit dd23072

Please sign in to comment.