diff --git a/.vscode/launch.json b/.vscode/launch.json index 2b3a8dff3..b7718125c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,23 +19,6 @@ "script": "watch" } }, - { - "name": "Launch Preview", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--disable-extensions", - "--extensionDevelopmentPath=${workspaceRoot}/packages/vscode-vue-preview" - ], - "outFiles": [ - "${workspaceRoot}/*/*/out/**/*.js" - ], - "preLaunchTask": { - "type": "npm", - "script": "watch" - } - }, { "type": "extensionHost", "request": "launch", diff --git a/README.md b/README.md index d9e17c019..57797cf0b 100644 --- a/README.md +++ b/README.md @@ -132,8 +132,6 @@ flowchart LR VOLAR_VUE_SERVICE["@volar/vue-language-service"] VOLAR_PUG_SERVICE["@volar/pug-language-service"] VOLAR_TS_SERVICE["@volar/typescript-language-service"] - %% VOLAR_TS_FASTER["@volar/typescript-faster"] - %% VOLAR_PREVIEW["@volar/preview"] VUE_TSC[vue-tsc] VUE_COMPONENT_META[vue-component-meta] TS_VUE_PLUGIN[typescript-vue-plugin] @@ -148,7 +146,6 @@ flowchart LR click VOLAR_PUG_SERVICE "https://github.com/johnsoncodehk/volar/tree/master/packages/pug-language-service" click VOLAR_TS_SERVICE "https://github.com/johnsoncodehk/volar/tree/master/packages/typescript-language-service" click VOLAR_TS_FASTER "https://github.com/johnsoncodehk/volar/tree/master/packages/typescript-faster" - click VOLAR_PREVIEW "https://github.com/johnsoncodehk/volar/tree/master/packages/preview" %% Extrnal Packages HTML_SERVICE[vscode-html-languageservice] @@ -209,9 +206,6 @@ flowchart LR VIM_VUE --> VUE_CLIENTS LAPCE_VUE --> VUE_CLIENTS - %% VSC_VUE --> VOLAR_PREVIEW - %% COC_VUE --> VOLAR_PREVIEW - VUE_CLIENTS -- Language Server Protocol --> VOLAR_VUE_SERVER VSC --> VSC_TS diff --git a/package.json b/package.json index 7f01e655a..2f098c3ff 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,9 @@ "scripts": { "build": "tsc -b tsconfig.build.json", "build-ci": "tsc -b tsconfig.build-ci.json", - "watch": "npm run build && (npm run watch:base & npm run watch:vue & npm run watch:vue-preview & npm run watch:typescript-vue-plugin)", + "watch": "npm run build && (npm run watch:base & npm run watch:vue & npm run watch:typescript-vue-plugin)", "watch:base": "tsc -b tsconfig.build.json -w", "watch:vue": "cd ./packages/vscode-vue && npm run watch", - "watch:vue-preview": "cd ./packages/vscode-vue-preview && npm run watch", "watch:typescript-vue-plugin": "cd ./packages/vscode-typescript-vue-plugin && npm run watch", "prerelease": "npm run build && npm run test", "version:test": "lerna version --exact --force-publish --yes --sync-workspace-lock --no-push --no-git-tag-version", diff --git a/packages/preview/LICENSE b/packages/preview/LICENSE deleted file mode 100644 index b55e47a7e..000000000 --- a/packages/preview/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021-present Johnson Chu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/preview/bin/nuxi.js b/packages/preview/bin/nuxi.js deleted file mode 100755 index e34ad1d1e..000000000 --- a/packages/preview/bin/nuxi.js +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env node - -const path = require('path'); -const fs = require('fs'); -const readFileSync = fs.readFileSync; - -const workspace = process.cwd(); -const nuxiBinPath = require.resolve('nuxi/cli', { paths: [workspace] }); -const jsConfigPath = path.resolve(workspace, 'nuxt.config.js'); -const tsConfigPath = path.resolve(workspace, 'nuxt.config.ts'); - -fs.readFileSync = (...args) => { - if (args[0] === jsConfigPath || args[0] === tsConfigPath) { - const configExtraContent = readFileSync(path.resolve(__dirname, 'nuxi', 'configExtraContent.ts'), { encoding: 'utf8' }); - return readFileSync(...args) + configExtraContent; - } - return readFileSync(...args); -}; - -createNuxtPlugin(); - -import('file://' + nuxiBinPath); - -function createNuxtPlugin() { - - if (!fs.existsSync(path.resolve(workspace, 'node_modules', '.volar'))) { - fs.mkdirSync(path.resolve(workspace, 'node_modules', '.volar')); - } - - const proxyConfigPath = path.resolve(workspace, 'node_modules', '.volar', 'nuxt.plugin.ts'); - const pluginContent = fs.readFileSync(path.resolve(__dirname, 'nuxi', 'plugin.ts'), { encoding: 'utf8' }); - - fs.writeFileSync(proxyConfigPath, pluginContent); -} diff --git a/packages/preview/bin/nuxi/configExtraContent.ts b/packages/preview/bin/nuxi/configExtraContent.ts deleted file mode 100644 index df21ff2b0..000000000 --- a/packages/preview/bin/nuxi/configExtraContent.ts +++ /dev/null @@ -1,53 +0,0 @@ - -if (!module.exports.default) - module.exports.default = {}; - -if (!module.exports.default.vue) - module.exports.default.vue = {}; - -if (!module.exports.default.vue.compilerOptions) - module.exports.default.vue.compilerOptions = {}; - -if (!module.exports.default.vue.compilerOptions.nodeTransforms) - module.exports.default.vue.compilerOptions.nodeTransforms = []; - -module.exports.default.vue.compilerOptions.nodeTransforms.push( - (node, ctx) => { - if (node.type === 1) { - const start = node.loc.start.offset; - const end = node.loc.end.offset; - addEvent(node, 'pointerenter', `$event ? $volar.highlight($event.target, $.type.__file, [${start},${end}]) : undefined`); - addEvent(node, 'pointerleave', '$event ? $volar.unHighlight($event.target) : undefined'); - addEvent(node, 'vnode-mounted', `$event ? $volar.vnodeMounted($event.el, $.type.__file, [${start},${end}]) : undefined`); - addEvent(node, 'vnode-unmounted', '$event ? $volar.vnodeUnmounted($event.el) : undefined'); - } - } -); - -if (!module.exports.default.plugins) - module.exports.default.plugins = []; - -module.exports.default.plugins.push({ src: './node_modules/.volar/nuxt.plugin.ts', ssr: false }); - -function addEvent(node, name: string, exp: string) { - node.props.push({ - type: 7, - name: 'on', - exp: { - type: 4, - content: exp, - isStatic: false, - constType: 0, - loc: node.loc, - }, - arg: { - type: 4, - content: name, - isStatic: true, - constType: 3, - loc: node.loc, - }, - modifiers: [], - loc: node.loc, - }); -} diff --git a/packages/preview/bin/nuxi/plugin.ts b/packages/preview/bin/nuxi/plugin.ts deleted file mode 100644 index 80f23f2e1..000000000 --- a/packages/preview/bin/nuxi/plugin.ts +++ /dev/null @@ -1,309 +0,0 @@ -// @ts-nocheck -// remove defineNuxtPlugin() to fixed https://github.com/yaegassy/coc-volar-tools/pull/3#issuecomment-1109155402 -export default app => { - - if (process.server) - return; - - const ws = new WebSocket('ws://localhost:56789'); - const finderApis = installGoToCode(); - const highlightApis = installSelectionHighlight(); - - return { - provide: { - volar: { - ...finderApis, - ...highlightApis, - }, - }, - }; - - function installSelectionHighlight() { - - let selection: { - fileName: string, - ranges: { - start, - end, - }[], - isDirty: boolean, - } | undefined; - let updateTimeout: number | undefined; - const nodes = new Map(); - const cursorInOverlays = new Map(); - const rangeCoverOverlays = new Map(); - const cursorInResizeObserver = new ResizeObserver(scheduleUpdate); - const rangeCoverResizeObserver = new ResizeObserver(scheduleUpdate); - - window.addEventListener('scroll', scheduleUpdate); - - ws.addEventListener('message', event => { - const data = JSON.parse(event.data); - if (data?.command === 'highlightSelections') { - selection = data.data; - updateHighlights(); - } - }); - - return { - vnodeMounted, - vnodeUnmounted, - }; - - function vnodeMounted(node: unknown, fileName: string, range: [number, number]) { - if (node instanceof Element) { - nodes.set(node, { - fileName, - range, - }); - scheduleUpdate(); - } - } - function vnodeUnmounted(node: unknown) { - if (node instanceof Element) { - nodes.delete(node); - scheduleUpdate(); - } - } - function scheduleUpdate() { - if (updateTimeout === undefined) { - updateTimeout = setTimeout(() => { - updateHighlights(); - updateTimeout = undefined; - }, 0); - } - } - function updateHighlights() { - - if (selection?.isDirty) { - for (const [_, overlay] of cursorInOverlays) { - overlay.style.opacity = '0.5'; - } - for (const [_, overlay] of rangeCoverOverlays) { - overlay.style.opacity = '0.5'; - } - return; - } - else { - for (const [_, overlay] of cursorInOverlays) { - overlay.style.opacity = '1'; - } - for (const [_, overlay] of rangeCoverOverlays) { - overlay.style.opacity = '1'; - } - } - - const cursorIn = new Set(); - const rangeConver = new Set(); - - if (selection) { - for (const range of selection.ranges) { - for (const [el, loc] of nodes) { - if (loc.fileName.replace(/\\/g, '/').toLowerCase() === selection.fileName.replace(/\\/g, '/').toLowerCase()) { - if (range.start <= loc.range[0] && range.end >= loc.range[1]) { - rangeConver.add(el); - } - else if ( - range.start >= loc.range[0] && range.start <= loc.range[1] - || range.end >= loc.range[0] && range.end <= loc.range[1] - ) { - cursorIn.add(el); - } - } - } - } - } - - for (const [el, overlay] of [...cursorInOverlays]) { - if (!cursorIn.has(el)) { - overlay.remove(); - cursorInOverlays.delete(el); - cursorInResizeObserver.disconnect(el); - } - } - for (const [el, overlay] of [...rangeCoverOverlays]) { - if (!rangeConver.has(el)) { - overlay.remove(); - rangeCoverOverlays.delete(el); - rangeCoverResizeObserver.disconnect(el); - } - } - - for (const el of cursorIn) { - let overlay = cursorInOverlays.get(el); - if (!overlay) { - overlay = createCursorInOverlay(); - cursorInOverlays.set(el, overlay); - cursorInResizeObserver.observe(el); - } - const rect = el.getBoundingClientRect(); - overlay.style.width = ~~rect.width + 'px'; - overlay.style.height = ~~rect.height + 'px'; - overlay.style.top = ~~rect.top + 'px'; - overlay.style.left = ~~rect.left + 'px'; - } - for (const el of rangeConver) { - let overlay = rangeCoverOverlays.get(el); - if (!overlay) { - overlay = createRangeCoverOverlay(); - rangeCoverOverlays.set(el, overlay); - rangeCoverResizeObserver.observe(el); - } - const rect = el.getBoundingClientRect(); - overlay.style.width = ~~rect.width + 'px'; - overlay.style.height = ~~rect.height + 'px'; - overlay.style.top = ~~rect.top + 'px'; - overlay.style.left = ~~rect.left + 'px'; - } - } - function createCursorInOverlay() { - const overlay = document.createElement('div'); - overlay.style.position = 'fixed'; - overlay.style.zIndex = '99999999999999'; - overlay.style.pointerEvents = 'none'; - overlay.style.borderRadius = '3px'; - overlay.style.borderStyle = 'dashed'; - overlay.style.borderColor = 'rgb(196, 105, 183)'; - overlay.style.borderWidth = '1px'; - overlay.style.boxSizing = 'border-box'; - document.body.appendChild(overlay); - return overlay; - } - function createRangeCoverOverlay() { - const overlay = createCursorInOverlay(); - overlay.style.backgroundColor = 'rgba(196, 105, 183, 0.1)'; - return overlay; - } - } - - function installGoToCode() { - - window.addEventListener('scroll', updateOverlay); - window.addEventListener('pointerdown', event => { - disable(true); - }); - window.addEventListener('keydown', event => { - if (event.key === 'Alt') { - enable(); - } - }); - window.addEventListener('keyup', event => { - if (event.key === 'Alt') { - disable(false); - } - }); - - ws.addEventListener('message', event => { - const data = JSON.parse(event.data); - if (data?.command === 'openFile') { - window.open(data.data); - } - }); - - const overlay = createOverlay(); - const clickMask = createClickMask(); - - let highlightNodes: [Element, string, [number, number]][] = []; - let enabled = false; - let lastCodeLoc: any | undefined; - - return { - highlight, - unHighlight, - }; - - function enable() { - enabled = true; - clickMask.style.pointerEvents = 'none'; - document.body.appendChild(clickMask); - updateOverlay(); - } - function disable(openEditor: boolean) { - if (enabled) { - enabled = false; - clickMask.style.pointerEvents = ''; - highlightNodes = []; - updateOverlay(); - if (lastCodeLoc) { - ws.send(JSON.stringify(lastCodeLoc)); - if (openEditor) { - ws.send(JSON.stringify({ - command: 'requestOpenFile', - data: lastCodeLoc.data, - })); - } - lastCodeLoc = undefined; - } - } - } - function goToTemplate(fileName: string, range: [number, number]) { - if (!enabled) return; - lastCodeLoc = { - command: 'goToTemplate', - data: { - fileName, - range, - }, - }; - ws.send(JSON.stringify(lastCodeLoc)); - } - function highlight(node: unknown, fileName: string, range: [number, number]) { - if (node instanceof Element) { - highlightNodes.push([node, fileName, range]); - } - updateOverlay(); - } - function unHighlight(node: Element) { - highlightNodes = highlightNodes.filter(hNode => hNode[0] !== node); - updateOverlay(); - } - function createOverlay() { - const overlay = document.createElement('div'); - overlay.style.backgroundColor = 'rgba(65, 184, 131, 0.35)'; - overlay.style.position = 'fixed'; - overlay.style.zIndex = '99999999999999'; - overlay.style.pointerEvents = 'none'; - overlay.style.display = 'flex'; - overlay.style.alignItems = 'center'; - overlay.style.justifyContent = 'center'; - overlay.style.borderRadius = '3px'; - return overlay; - } - function createClickMask() { - const overlay = document.createElement('div'); - overlay.style.position = 'fixed'; - overlay.style.zIndex = '99999999999999'; - overlay.style.pointerEvents = 'none'; - overlay.style.display = 'flex'; - overlay.style.left = '0'; - overlay.style.right = '0'; - overlay.style.top = '0'; - overlay.style.bottom = '0'; - overlay.addEventListener('pointerup', () => { - if (overlay.parentNode) { - overlay.parentNode?.removeChild(overlay); - } - }); - return overlay; - } - function updateOverlay() { - if (enabled && highlightNodes.length) { - document.body.appendChild(overlay); - const highlight = highlightNodes[highlightNodes.length - 1]; - const highlightNode = highlight[0]; - const rect = highlightNode.getBoundingClientRect(); - overlay.style.width = ~~rect.width + 'px'; - overlay.style.height = ~~rect.height + 'px'; - overlay.style.top = ~~rect.top + 'px'; - overlay.style.left = ~~rect.left + 'px'; - goToTemplate(highlight[1], highlight[2]); - } - else if (overlay.parentNode) { - overlay.parentNode.removeChild(overlay); - } - } - } -}; diff --git a/packages/preview/bin/vite.js b/packages/preview/bin/vite.js deleted file mode 100755 index 1e5ae1391..000000000 --- a/packages/preview/bin/vite.js +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env node - -const path = require('path'); -const fs = require('fs'); - -const workspace = process.cwd(); -const vitePkgPath = require.resolve('vite/package.json', { paths: [workspace] }); -const viteDir = path.dirname(vitePkgPath); -const viteBinPath = require.resolve('./bin/vite.js', { paths: [viteDir] }); -const viteVersion = require(vitePkgPath).version; - -try { - const vuePluginPath = require.resolve('@vitejs/plugin-vue', { paths: [workspace] }); - const viteExtraCode = ` -function __proxyExport(rawOptions = {}) { - - if (!rawOptions) - rawOptions = {}; - - if (!rawOptions.template) - rawOptions.template = {}; - - if (!rawOptions.template.compilerOptions) - rawOptions.template.compilerOptions = {}; - - if (!rawOptions.template.compilerOptions.nodeTransforms) - rawOptions.template.compilerOptions.nodeTransforms = []; - - rawOptions.template.compilerOptions.nodeTransforms.push((node, ctx) => { - if (node.type === 1) { - const start = node.loc.start.offset; - const end = node.loc.end.offset; - addEvent(node, 'pointerenter', \`$event ? $volar.highlight($event.target, $.type.__file, [\${start},\${end}]) : undefined\`); - addEvent(node, 'pointerleave', '$event ? $volar.unHighlight($event.target) : undefined'); - addEvent(node, 'vnode-mounted', \`$event ? $volar.vnodeMounted($event.el, $.type.__file, [\${start},\${end}]) : undefined\`); - addEvent(node, 'vnode-unmounted', '$event ? $volar.vnodeUnmounted($event.el) : undefined'); - } - }); - - return __originalExport(rawOptions); - - function addEvent(node, name, exp) { - node.props.push({ - type: 7, - name: 'on', - exp: { - type: 4, - content: exp, - isStatic: false, - constType: 0, - loc: node.loc, - }, - arg: { - type: 4, - content: name, - isStatic: true, - constType: 3, - loc: node.loc, - }, - modifiers: [], - loc: node.loc, - }); - } -} - -const __originalExport = module.exports; -module.exports = __proxyExport; -`; - - const readFileSync = fs.readFileSync; - fs.readFileSync = (...args) => { - if (args[0] === vuePluginPath) { - return readFileSync(...args) + viteExtraCode; - } - return readFileSync(...args); - }; -} catch (e) { - console.warn('Volar: @vitejs/plugin-vue not found, skip vite extra code. (vue@2 only)') -} - -createViteConfig(); - -if (Number(viteVersion.split('.')[0]) >= 3) { - import('file://' + viteBinPath); -} -else { - require(viteBinPath); -} - -function createViteConfig() { - let proxyConfigContent = fs.readFileSync(path.resolve(__dirname, 'vite', 'config.ts'), { encoding: 'utf8' }); - proxyConfigContent = proxyConfigContent.replace('{CONFIG_PATH}', JSON.stringify(path.resolve(workspace, 'vite.config'))); - - if (!fs.existsSync(path.resolve(workspace, 'node_modules', '.volar'))) { - fs.mkdirSync(path.resolve(workspace, 'node_modules', '.volar')); - } - - const proxyConfigPath = path.resolve(workspace, 'node_modules', '.volar', 'vite.config.ts'); - fs.writeFileSync(proxyConfigPath, proxyConfigContent); - - process.argv.push('--config', proxyConfigPath); -} diff --git a/packages/preview/bin/vite/config.ts b/packages/preview/bin/vite/config.ts deleted file mode 100644 index 5ad8c4295..000000000 --- a/packages/preview/bin/vite/config.ts +++ /dev/null @@ -1,319 +0,0 @@ -// @ts-nocheck -import config from {CONFIG_PATH}; - -if (!config.plugins) - config.plugins = []; - -const installCode = ` -function __createAppProxy(...args) { - - const app = createApp(...args); - - const ws = new WebSocket('ws://localhost:56789'); - const finderApis = installGoToCode(); - const highlightApis = installSelectionHighlight(); - - app.config.globalProperties.$volar = { - ...finderApis, - ...highlightApis, - }; - - return app; - - function installSelectionHighlight() { - - let selection; - let updateTimeout; - const nodes = new Map(); - const cursorInOverlays = new Map(); - const rangeCoverOverlays = new Map(); - const cursorInResizeObserver = new ResizeObserver(scheduleUpdate); - const rangeCoverResizeObserver = new ResizeObserver(scheduleUpdate); - - window.addEventListener('scroll', scheduleUpdate); - - ws.addEventListener('message', event => { - const data = JSON.parse(event.data); - if (data?.command === 'highlightSelections') { - selection = data.data; - updateHighlights(); - } - }); - - return { - vnodeMounted, - vnodeUnmounted, - }; - - function vnodeMounted(node, fileName, range) { - if (node instanceof Element) { - nodes.set(node, { - fileName, - range, - }); - scheduleUpdate(); - } - } - function vnodeUnmounted(node) { - if (node instanceof Element) { - nodes.delete(node); - scheduleUpdate(); - } - } - function scheduleUpdate() { - if (updateTimeout === undefined) { - updateTimeout = setTimeout(() => { - updateHighlights(); - updateTimeout = undefined; - }, 0); - } - } - function updateHighlights() { - - if (selection?.isDirty) { - for (const [_, overlay] of cursorInOverlays) { - overlay.style.opacity = '0.5'; - } - for (const [_, overlay] of rangeCoverOverlays) { - overlay.style.opacity = '0.5'; - } - return; - } - else { - for (const [_, overlay] of cursorInOverlays) { - overlay.style.opacity = '1'; - } - for (const [_, overlay] of rangeCoverOverlays) { - overlay.style.opacity = '1'; - } - } - - const cursorIn = new Set(); - const rangeConver = new Set(); - - if (selection) { - for (const range of selection.ranges) { - for (const [el, loc] of nodes) { - if (loc.fileName === selection.fileName) { - if (range.start <= loc.range[0] && range.end >= loc.range[1]) { - rangeConver.add(el); - } - else if ( - range.start >= loc.range[0] && range.start <= loc.range[1] - || range.end >= loc.range[0] && range.end <= loc.range[1] - ) { - cursorIn.add(el); - } - } - } - } - } - - for (const [el, overlay] of [...cursorInOverlays]) { - if (!cursorIn.has(el)) { - overlay.remove(); - cursorInOverlays.delete(el); - cursorInResizeObserver.disconnect(el); - } - } - for (const [el, overlay] of [...rangeCoverOverlays]) { - if (!rangeConver.has(el)) { - overlay.remove(); - rangeCoverOverlays.delete(el); - rangeCoverResizeObserver.disconnect(el); - } - } - - for (const el of cursorIn) { - let overlay = cursorInOverlays.get(el); - if (!overlay) { - overlay = createCursorInOverlay(); - cursorInOverlays.set(el, overlay); - cursorInResizeObserver.observe(el); - } - const rect = el.getBoundingClientRect(); - overlay.style.width = ~~rect.width + 'px'; - overlay.style.height = ~~rect.height + 'px'; - overlay.style.top = ~~rect.top + 'px'; - overlay.style.left = ~~rect.left + 'px'; - } - for (const el of rangeConver) { - let overlay = rangeCoverOverlays.get(el); - if (!overlay) { - overlay = createRangeCoverOverlay(); - rangeCoverOverlays.set(el, overlay); - rangeCoverResizeObserver.observe(el); - } - const rect = el.getBoundingClientRect(); - overlay.style.width = ~~rect.width + 'px'; - overlay.style.height = ~~rect.height + 'px'; - overlay.style.top = ~~rect.top + 'px'; - overlay.style.left = ~~rect.left + 'px'; - } - } - function createCursorInOverlay() { - const overlay = document.createElement('div'); - overlay.style.position = 'fixed'; - overlay.style.zIndex = '99999999999999'; - overlay.style.pointerEvents = 'none'; - overlay.style.borderRadius = '3px'; - overlay.style.borderStyle = 'dashed'; - overlay.style.borderColor = 'rgb(196, 105, 183)'; - overlay.style.borderWidth = '1px'; - overlay.style.boxSizing = 'border-box'; - document.body.appendChild(overlay); - return overlay; - } - function createRangeCoverOverlay() { - const overlay = createCursorInOverlay(); - overlay.style.backgroundColor = 'rgba(196, 105, 183, 0.1)'; - return overlay; - } - } - function installGoToCode() { - window.addEventListener('scroll', updateOverlay); - window.addEventListener('pointerdown', function (ev) { - disable(true); - }); - window.addEventListener('keydown', event => { - if (event.key === 'Alt') { - enable(); - } - }); - window.addEventListener('keyup', event => { - if (event.key === 'Alt') { - disable(false); - } - }); - - ws.addEventListener('message', event => { - const data = JSON.parse(event.data); - if (data?.command === 'openFile') { - window.open(data.data); - } - }); - - var overlay = createOverlay(); - var clickMask = createClickMask(); - var highlightNodes = []; - var enabled = false; - var lastCodeLoc; - - return { - highlight, - unHighlight, - }; - - function enable() { - enabled = true; - clickMask.style.pointerEvents = 'none'; - document.body.appendChild(clickMask); - updateOverlay(); - } - function disable(openEditor) { - if (enabled) { - enabled = false; - clickMask.style.pointerEvents = ''; - highlightNodes = []; - updateOverlay(); - if (lastCodeLoc) { - ws.send(JSON.stringify(lastCodeLoc)); - if (openEditor) { - ws.send(JSON.stringify({ - command: 'requestOpenFile', - data: lastCodeLoc.data, - })); - } - lastCodeLoc = undefined; - } - } - } - function goToTemplate(fileName, range) { - if (!enabled) - return; - lastCodeLoc = { - command: 'goToTemplate', - data: { - fileName: fileName, - range, - }, - }; - ws.send(JSON.stringify(lastCodeLoc)); - } - function highlight(node, fileName, range) { - if (node instanceof Element) { - highlightNodes.push([node, fileName, range]); - } - updateOverlay(); - } - function unHighlight(node) { - highlightNodes = highlightNodes.filter(function (hNode) { return hNode[0] !== node; }); - updateOverlay(); - } - function createOverlay() { - var overlay = document.createElement('div'); - overlay.style.backgroundColor = 'rgba(65, 184, 131, 0.35)'; - overlay.style.position = 'fixed'; - overlay.style.zIndex = '99999999999999'; - overlay.style.pointerEvents = 'none'; - overlay.style.display = 'flex'; - overlay.style.alignItems = 'center'; - overlay.style.justifyContent = 'center'; - overlay.style.borderRadius = '3px'; - return overlay; - } - function createClickMask() { - var overlay = document.createElement('div'); - overlay.style.position = 'fixed'; - overlay.style.zIndex = '99999999999999'; - overlay.style.pointerEvents = 'none'; - overlay.style.display = 'flex'; - overlay.style.left = '0'; - overlay.style.right = '0'; - overlay.style.top = '0'; - overlay.style.bottom = '0'; - overlay.addEventListener('pointerup', function () { - var _a; - if (overlay.parentNode) { - (_a = overlay.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(overlay); - } - }); - return overlay; - } - function updateOverlay() { - if (enabled && highlightNodes.length) { - document.body.appendChild(overlay); - var highlight_1 = highlightNodes[highlightNodes.length - 1]; - var highlightNode = highlight_1[0]; - var rect = highlightNode.getBoundingClientRect(); - overlay.style.width = ~~rect.width + 'px'; - overlay.style.height = ~~rect.height + 'px'; - overlay.style.top = ~~rect.top + 'px'; - overlay.style.left = ~~rect.left + 'px'; - goToTemplate(highlight_1[1], highlight_1[2]); - } - else if (overlay.parentNode) { - overlay.parentNode.removeChild(overlay); - } - } - } -} -`; - -config.plugins.push({ - name: '__volar_preview', - transform(this, code, id, options?) { - const createAppText = 'createApp,'; - if (id.indexOf('/vue.js?') >= 0 && code.indexOf(createAppText) >= 0 && code.indexOf('__createAppProxy') === -1) { - const createAppOffset = code.lastIndexOf(createAppText); - code = - code.substring(0, createAppOffset) - + '__createAppProxy as createApp,' - + code.substring(createAppOffset + createAppText.length) - + `${installCode}`; - } - return code; - }, -}); - -export default config; diff --git a/packages/preview/package.json b/packages/preview/package.json deleted file mode 100644 index 4f3b6d1f9..000000000 --- a/packages/preview/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "@volar/preview", - "version": "1.0.24", - "license": "MIT", - "files": [ - "bin", - "out/**/*.js", - "out/**/*.d.ts" - ], - "repository": { - "type": "git", - "url": "https://github.com/johnsoncodehk/volar.git", - "directory": "packages/preview" - }, - "main": "out/index.js", - "bin": { - "volar-preview-vite": "./bin/vite.js", - "volar-preview-nuxi": "./bin/nuxi.js" - }, - "devDependencies": { - "@types/ws": "^8.5.4" - }, - "dependencies": { - "ws": "^8.12.0" - } -} diff --git a/packages/preview/src/index.ts b/packages/preview/src/index.ts deleted file mode 100644 index 3240b65be..000000000 --- a/packages/preview/src/index.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as WebSocket from 'ws'; - -export function createPreviewConnection(options: { - onGotoCode: (fileName: string, range: [number, number], cancelToken: { readonly isCancelled: boolean; }) => void, - getFileHref: (fileName: string, range: [number, number]) => string, -}) { - - const wsList: WebSocket.WebSocket[] = []; - let wss: WebSocket.Server | undefined; - let goToTemplateReq = 0; - - wss = new WebSocket.Server({ port: 56789 }); - wss.on('connection', ws => { - - wsList.push(ws); - - ws.on('message', msg => { - - const message = JSON.parse(msg.toString()); - - if (message.command === 'goToTemplate') { - - const req = ++goToTemplateReq; - const data = message.data as { - fileName: string, - range: [number, number], - }; - const token = { - get isCancelled() { - return req !== goToTemplateReq; - } - }; - - options.onGotoCode(data.fileName, data.range, token); - } - - if (message.command === 'requestOpenFile') { - - const data = message.data as { - fileName: string, - range: [number, number], - }; - const url = options.getFileHref(data.fileName, data.range); - - ws.send(JSON.stringify({ - command: 'openFile', - data: url, - })); - } - }); - }); - - return { - stop, - highlight, - unhighlight, - }; - - function stop() { - wss?.close(); - wsList.length = 0; - } - - function highlight(fileName: string, ranges: { start: number, end: number; }[], isDirty: boolean) { - const msg = { - command: 'highlightSelections', - data: { - fileName, - ranges, - isDirty, - }, - }; - for (const ws of wsList) { - ws.send(JSON.stringify(msg)); - } - } - - function unhighlight() { - const msg = { - command: 'highlightSelections', - data: undefined, - }; - for (const ws of wsList) { - ws.send(JSON.stringify(msg)); - } - } -} diff --git a/packages/preview/tsconfig.build.json b/packages/preview/tsconfig.build.json deleted file mode 100644 index 91865b53a..000000000 --- a/packages/preview/tsconfig.build.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "noEmit": false, - "outDir": "out", - "rootDir": "src", - }, - "include": [ - "src" - ], - "exclude": [ - "node_modules", - ".vscode-test" - ], -} \ No newline at end of file diff --git a/packages/vscode-vue-preview/.vscodeignore b/packages/vscode-vue-preview/.vscodeignore deleted file mode 100644 index aa3dc0da9..000000000 --- a/packages/vscode-vue-preview/.vscodeignore +++ /dev/null @@ -1,5 +0,0 @@ -out -src -scripts -tsconfig.build.json -tsconfig.build.tsbuildinfo diff --git a/packages/vscode-vue-preview/LICENSE b/packages/vscode-vue-preview/LICENSE deleted file mode 100644 index b55e47a7e..000000000 --- a/packages/vscode-vue-preview/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021-present Johnson Chu - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/vscode-vue-preview/images/nuxt-logo.svg b/packages/vscode-vue-preview/images/nuxt-logo.svg deleted file mode 100644 index cdba56891..000000000 --- a/packages/vscode-vue-preview/images/nuxt-logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/vscode-vue-preview/images/preview-bg.png b/packages/vscode-vue-preview/images/preview-bg.png deleted file mode 100644 index ebf6d919f..000000000 Binary files a/packages/vscode-vue-preview/images/preview-bg.png and /dev/null differ diff --git a/packages/vscode-vue-preview/images/vite-logo.svg b/packages/vscode-vue-preview/images/vite-logo.svg deleted file mode 100644 index de4aeddc1..000000000 --- a/packages/vscode-vue-preview/images/vite-logo.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/packages/vscode-vue-preview/package.json b/packages/vscode-vue-preview/package.json deleted file mode 100644 index b299946ba..000000000 --- a/packages/vscode-vue-preview/package.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "private": true, - "name": "vscode-vue-preview", - "version": "1.0.24", - "repository": { - "type": "git", - "url": "https://github.com/johnsoncodehk/volar.git", - "directory": "packages/vscode-vue-preview" - }, - "sponsor": { - "url": "https://github.com/sponsors/johnsoncodehk" - }, - "displayName": "Vue and Nuxt Preview (from Volar)", - "description": "Component and App Preview For Vue and Nuxt", - "author": "johnsoncodehk", - "publisher": "johnsoncodehk", - "engines": { - "vscode": "^1.67.0" - }, - "activationEvents": [ - "onLanguage:vue", - "onWebviewPanel:preview" - ], - "main": "./dist/extension.js", - "contributes": { - "views": { - "explorer": [ - { - "id": "vueComponentPreview", - "name": "Vue Component Preview", - "type": "webview", - "when": "volar.foundViteDir || volar.foundNuxtDir" - } - ] - }, - "languages": [ - { - "id": "vue", - "extensions": [ - ".vue" - ] - } - ], - "configuration": { - "type": "object", - "title": "Volar", - "properties": { - "volar.preview.script.vite": { - "type": "string", - "default": "node {VITE_BIN} --port={PORT}" - }, - "volar.preview.script.nuxi": { - "type": "string", - "default": "node {NUXI_BIN} dev --port {PORT}" - }, - "volar.preview.port": { - "type": "number", - "default": 3333, - "description": "Default port for component preview server." - }, - "volar.preview.root": { - "type": "string", - "default": ".", - "description": "Component preview root directory. (For Nuxt, it should be \"./src\" by default.)" - }, - "volar.preview.backgroundColor": { - "type": "string", - "default": "#fff", - "description": "Component preview background color." - }, - "volar.preview.transparentGrid": { - "type": "boolean", - "default": false, - "description": "Component preview background style." - } - } - }, - "commands": [ - { - "command": "volar.action.vite", - "title": "Experimental Features for Vite", - "category": "Volar", - "icon": "images/vite-logo.svg" - }, - { - "command": "volar.action.nuxt", - "title": "Experimental Features for Nuxt", - "category": "Volar", - "icon": "images/nuxt-logo.svg" - } - ], - "menus": { - "commandPalette": [ - { - "command": "volar.action.vite", - "when": "editorLangId == vue" - }, - { - "command": "volar.action.nuxt", - "when": "editorLangId == vue" - } - ], - "editor/title": [ - { - "command": "volar.action.vite", - "when": "editorLangId == vue && config.volar.icon.preview && volar.foundViteDir", - "group": "navigation" - }, - { - "command": "volar.action.nuxt", - "when": "editorLangId == vue && config.volar.icon.preview && volar.foundNuxtDir", - "group": "navigation" - } - ] - } - }, - "scripts": { - "prebuild": "cd ../.. && npm run build", - "build": "node scripts/build", - "watch": "npm run build -- --watch", - "prepack": "npm run prebuild && npm run build -- --minify", - "pack": "npm run prepack && vsce package", - "release": "npm run prepack && vsce publish" - }, - "devDependencies": { - "@types/vscode": "1.67.0", - "@volar/preview": "1.0.24", - "@volar/vscode-language-client": "1.2.0-alpha.9", - "esbuild": "0.15.18", - "esbuild-plugin-copy": "latest", - "typesafe-path": "^0.2.2", - "vscode-html-languageservice": "^5.0.4", - "vsce": "latest" - } -} diff --git a/packages/vscode-vue-preview/scripts/build.js b/packages/vscode-vue-preview/scripts/build.js deleted file mode 100644 index 3e98bd5fd..000000000 --- a/packages/vscode-vue-preview/scripts/build.js +++ /dev/null @@ -1,38 +0,0 @@ -require('esbuild').build({ - entryPoints: { - extension: './out/extension.js', - }, - bundle: true, - metafile: process.argv.includes('--metafile'), - outdir: './dist', - external: [ - 'vscode', - ], - format: 'cjs', - platform: 'node', - tsconfig: '../../tsconfig.build.json', - define: { 'process.env.NODE_ENV': '"production"' }, - minify: process.argv.includes('--minify'), - watch: process.argv.includes('--watch'), - plugins: [ - { - name: 'umd2esm', - setup(build) { - build.onResolve({ filter: /^(vscode-.*|estree-walker|jsonc-parser)/ }, args => { - const pathUmdMay = require.resolve(args.path, { paths: [args.resolveDir] }) - // Call twice the replace is to solve the problem of the path in Windows - const pathEsm = pathUmdMay.replace('/umd/', '/esm/').replace('\\umd\\', '\\esm\\') - return { path: pathEsm } - }) - }, - }, - require('esbuild-plugin-copy').copy({ - resolveFrom: 'cwd', - assets: { - from: ['./node_modules/@volar/preview/bin/**/*'], - to: ['./dist/bin'], - }, - keepStructure: true, - }), - ], -}).catch(() => process.exit(1)) diff --git a/packages/vscode-vue-preview/src/extension.ts b/packages/vscode-vue-preview/src/extension.ts deleted file mode 100644 index fb8fe1ce2..000000000 --- a/packages/vscode-vue-preview/src/extension.ts +++ /dev/null @@ -1,625 +0,0 @@ -import * as vscode from 'vscode'; -import * as path from 'typesafe-path'; -import * as fs from './utils/fs'; -import { quickPick } from '@volar/vscode-language-client/out/common'; -import * as preview from '@volar/preview'; -import { getLocalHostAvailablePort } from './utils/http'; -import * as html from 'vscode-html-languageservice'; - -const htmlLs = html.getLanguageService(); - -const enum PreviewType { - Webview = 'volar-webview', - ExternalBrowser = 'volar-start-server', - ExternalBrowser_Component = 'volar-component-preview', -} - -export async function activate(context: vscode.ExtensionContext) { - - let _loadingPanel: vscode.WebviewPanel | undefined; - let avoidUpdateOnDidChangeActiveTextEditor = false; - let updateComponentPreview: Function | undefined; - - const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, -1); - statusBar.command = 'volar.previewMenu'; - statusBar.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); - context.subscriptions.push(statusBar); - - let connection: ReturnType | undefined; - let highlightDomElements = true; - - const previewTerminal = vscode.window.terminals.find(terminal => terminal.name.startsWith('volar-preview:')); - if (previewTerminal) { - connection = preview.createPreviewConnection({ - onGotoCode: handleGoToCode, - getFileHref: (fileName) => { - avoidUpdateOnDidChangeActiveTextEditor = false; - updateComponentPreview?.(); - return 'vscode://files:/' + fileName; - }, - }); - statusBar.text = 'Preview Port: ' + previewTerminal.name.split(':')[2]; - statusBar.show(); - } - vscode.window.onDidOpenTerminal(e => { - if (e.name.startsWith('volar-preview:')) { - connection = preview.createPreviewConnection({ - onGotoCode: handleGoToCode, - getFileHref: (fileName) => { - avoidUpdateOnDidChangeActiveTextEditor = false; - updateComponentPreview?.(); - return 'vscode://files:/' + fileName; - }, - }); - statusBar.text = 'Preview Port: ' + e.name.split(':')[2]; - statusBar.show(); - } - }); - vscode.window.onDidCloseTerminal(e => { - if (e.name.startsWith('volar-preview:')) { - connection?.stop(); - connection = undefined; - statusBar.hide(); - } - }); - - const templateOffsets = new WeakMap(); - - class VueComponentPreview implements vscode.WebviewViewProvider { - - public resolveWebviewView( - webviewView: vscode.WebviewView, - _context: vscode.WebviewViewResolveContext, - _token: vscode.CancellationToken, - ) { - - let lastPreviewDocument: vscode.TextDocument | undefined; - let updating: Promise | undefined; - - webviewView.webview.options = { - enableScripts: true, - }; - updateWebView(true); - updateComponentPreview = updateWebView; - - vscode.window.onDidChangeActiveTextEditor(() => { - if (avoidUpdateOnDidChangeActiveTextEditor) - return; - if (!vscode.window.activeTextEditor || lastPreviewDocument === vscode.window.activeTextEditor.document) - return; - updateWebView(false); - }); - vscode.workspace.onDidChangeTextDocument(() => updateWebView(false)); - vscode.workspace.onDidChangeConfiguration(() => updateWebView(true)); - - webviewView.onDidChangeVisibility(() => updateWebView(false)); - - function updateWebView(refresh: boolean) { - if (updating) { - updating = updating.then(() => updateWebViewWorker(refresh)); - } - else { - updating = updateWebViewWorker(refresh); - } - } - - async function updateWebViewWorker(refresh: boolean) { - - if (!webviewView.visible) - return; - - if (vscode.window.activeTextEditor?.document.languageId === 'vue') - lastPreviewDocument = vscode.window.activeTextEditor.document; - - if (!lastPreviewDocument) - return; - - const fileName = lastPreviewDocument.fileName as path.OsPath; - let terminal = vscode.window.terminals.find(terminal => terminal.name.startsWith('volar-preview:')); - let port: number; - let configFile = await getConfigFile(fileName, 'vite'); - let previewMode: 'vite' | 'nuxt' = 'vite'; - - if (!configFile) { - configFile = await getConfigFile(fileName, 'nuxt'); - previewMode = 'nuxt'; - } - if (!configFile) - return; - - if (terminal) { - port = Number(terminal.name.split(':')[2]); - } - else { - const configDir = path.dirname(configFile); - const server = await startPreviewServer(configDir, previewMode); - terminal = server.terminal; - port = server.port; - } - - const root = vscode.workspace.getConfiguration('volar').get('preview.root')!; - const relativePath = path.relative(path.resolve(path.dirname(configFile), root), fileName).replace(/\\/g, '/'); - let url = `http://localhost:${port}/__preview${relativePath}#`; - - if (lastPreviewDocument.isDirty) { - url += btoa(lastPreviewDocument.getText()); - } - - if (refresh) { - - const bgPath = vscode.Uri.file(path.join(context.extensionPath as path.OsPath, 'images/preview-bg.png' as path.PosixPath)); - const bgSrc = webviewView.webview.asWebviewUri(bgPath); - - webviewView.webview.html = ''; - webviewView.webview.html = getWebviewContent(url, bgSrc.toString()); - } - else { - webviewView.webview.postMessage({ - sender: 'volar', - command: 'updateUrl', - data: url, - }); - } - } - } - } - - vscode.window.registerWebviewViewProvider( - 'vueComponentPreview', - new VueComponentPreview(), - ); - - context.subscriptions.push(vscode.commands.registerCommand('volar.previewMenu', async () => { - - const baseOptions: Record = {}; - const urlOptions: Record = {}; - const highlight: Record = {}; - - baseOptions['kill'] = { label: 'Kill Preview Server' }; - baseOptions['browser'] = { label: 'Open in Browser' }; - highlight['highlight-on'] = { label: (highlightDomElements ? '• ' : '') + 'Highlight DOM Elements' }; - highlight['highlight-off'] = { label: (!highlightDomElements ? '• ' : '') + `Don't Highlight DOM Elements` }; - - const key = await quickPick([baseOptions, urlOptions, highlight]); - - if (key === 'kill') { - for (const terminal of vscode.window.terminals) { - if (terminal.name.startsWith('volar-preview:')) { - terminal.dispose(); - } - } - } - if (key === 'browser') { - vscode.env.openExternal(vscode.Uri.parse('http://localhost:' + statusBar.text.split(':')[2].trim())); - } - if (key === 'highlight-on') { - highlightDomElements = true; - if (vscode.window.activeTextEditor) { - updateSelectionHighlights(vscode.window.activeTextEditor); - } - } - if (key === 'highlight-off') { - highlightDomElements = false; - if (vscode.window.activeTextEditor) { - updateSelectionHighlights(vscode.window.activeTextEditor); - } - } - })); - context.subscriptions.push(vscode.commands.registerCommand('volar.action.vite', async () => { - - const editor = vscode.window.activeTextEditor; - if (!editor) - return; - - const viteConfigFile = await getConfigFile(editor.document.fileName as path.OsPath, 'vite'); - const select = await quickPick({ - [PreviewType.Webview]: { - label: 'Preview Vite App', - detail: vscode.workspace.rootPath && viteConfigFile ? path.relative(vscode.workspace.rootPath as path.OsPath, viteConfigFile) : viteConfigFile, - description: 'Press `Alt` to use go to code feature', - }, - [PreviewType.ExternalBrowser]: { - label: 'Preview Vite App in External Browser', - detail: vscode.workspace.rootPath && viteConfigFile ? path.relative(vscode.workspace.rootPath as path.OsPath, viteConfigFile) : viteConfigFile, - description: 'Press `Alt` to use go to code feature', - }, - [PreviewType.ExternalBrowser_Component]: { - label: `Preview Component in External Browser`, - detail: vscode.workspace.rootPath ? path.relative(vscode.workspace.rootPath as path.OsPath, editor.document.fileName as path.OsPath) : editor.document.fileName, - }, - }); - if (select === undefined) - return; // cancel - - openPreview(select as PreviewType, editor.document.fileName as path.OsPath, 'vite'); - })); - context.subscriptions.push(vscode.commands.registerCommand('volar.action.nuxt', async () => { - - const editor = vscode.window.activeTextEditor; - if (!editor) - return; - - const viteConfigFile = await getConfigFile(editor.document.fileName as path.OsPath, 'nuxt'); - const root = vscode.workspace.getConfiguration('volar').get('preview.root')!; - const select = await quickPick({ - [PreviewType.Webview]: { - label: 'Preview Nuxt App', - detail: vscode.workspace.rootPath && viteConfigFile ? path.relative(vscode.workspace.rootPath as path.OsPath, viteConfigFile) : viteConfigFile, - }, - [PreviewType.ExternalBrowser]: { - label: 'Preview Nuxt App in External Browser', - detail: vscode.workspace.rootPath && viteConfigFile ? path.relative(vscode.workspace.rootPath as path.OsPath, viteConfigFile) : viteConfigFile, - description: 'Press `Alt` to use go to code in Browser', - }, - [PreviewType.ExternalBrowser_Component]: { - label: `Preview Component in External Browser`, - detail: vscode.workspace.rootPath ? path.relative(path.resolve(vscode.workspace.rootPath as path.OsPath, root), editor.document.fileName as path.OsPath) : editor.document.fileName, - }, - }); - if (select === undefined) - return; // cancel - - openPreview(select as PreviewType, editor.document.fileName as path.OsPath, 'nuxt'); - })); - context.subscriptions.push(vscode.window.onDidChangeTextEditorSelection(e => { - updateSelectionHighlights(e.textEditor); - })); - context.subscriptions.push(vscode.workspace.onDidChangeTextDocument((e) => { - if (vscode.window.activeTextEditor?.document === e.document) { - updateSelectionHighlights(vscode.window.activeTextEditor); - } - })); - context.subscriptions.push(vscode.workspace.onDidSaveTextDocument((document) => { - if (vscode.window.activeTextEditor?.document === document) { - updateSelectionHighlights(vscode.window.activeTextEditor); - } - })); - - context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(updatePreviewIconStatus)); - - updatePreviewIconStatus(); - - function getTemplateOffset(document: vscode.TextDocument) { - let cache = templateOffsets.get(document); - if (!cache || cache.version !== document.version) { - templateOffsets.delete(document); - const htmlDocument = htmlLs.parseHTMLDocument(html.TextDocument.create(document.uri.toString(), document.languageId, document.version, document.getText())); - const template = htmlDocument.roots.find(node => node.tag === 'template'); - if (template?.startTagEnd !== undefined) { - templateOffsets.set(document, { - version: document.version, - offset: template.startTagEnd, - }); - } - } - return templateOffsets.get(document)?.offset ?? 0; - } - - async function updatePreviewIconStatus() { - if (vscode.window.activeTextEditor?.document.languageId === 'vue') { - - const viteConfigFile = await getConfigFile(vscode.window.activeTextEditor.document.fileName as path.OsPath, 'vite'); - const nuxtConfigFile = await getConfigFile(vscode.window.activeTextEditor.document.fileName as path.OsPath, 'nuxt'); - - vscode.commands.executeCommand('setContext', 'volar.foundViteDir', viteConfigFile !== undefined); - vscode.commands.executeCommand('setContext', 'volar.foundNuxtDir', nuxtConfigFile !== undefined); - } - } - - async function updateSelectionHighlights(textEditor: vscode.TextEditor) { - if (connection && textEditor.document.languageId === 'vue' && highlightDomElements) { - const offset = await getTemplateOffset(textEditor.document); - connection.highlight( - textEditor.document.fileName, - textEditor.selections.map(selection => ({ - start: textEditor.document.offsetAt(selection.start) - offset, - end: textEditor.document.offsetAt(selection.end) - offset, - })), - textEditor.document.isDirty, - ); - } - else { - connection?.unhighlight(); - } - } - - async function openPreview(previewType: PreviewType, fileName: path.OsPath, mode: 'vite' | 'nuxt', _panel?: vscode.WebviewPanel) { - - const configFile = await getConfigFile(fileName, mode); - if (!configFile) - return; - - let terminal = vscode.window.terminals.find(terminal => terminal.name.startsWith('volar-preview:')); - let port: number; - - if (terminal) { - port = Number(terminal.name.split(':')[2]); - } - else { - const configDir = path.dirname(configFile); - const server = await startPreviewServer(configDir, mode); - terminal = server.terminal; - port = server.port; - } - - const loadingPanel = _panel ?? vscode.window.createWebviewPanel( - previewType, - 'Preview ' + path.relative((vscode.workspace.rootPath ?? '') as path.OsPath, configFile), - vscode.ViewColumn.Beside, - { - retainContextWhenHidden: true, - enableScripts: true, - enableFindWidget: true, - }, - ); - - const panelContext: vscode.Disposable[] = []; - - loadingPanel.onDidDispose(() => { - for (const disposable of panelContext) { - disposable.dispose(); - } - }); - - panelContext.push(loadingPanel.webview.onDidReceiveMessage(webviewEventHandler)); - - terminal.show(); - _loadingPanel = loadingPanel; - - if (previewType === PreviewType.ExternalBrowser) { - loadingPanel.webview.html = getWebviewContent(`http://localhost:${port}`, undefined, 'openExternal'); - } - else if (previewType === PreviewType.ExternalBrowser_Component) { - const root = vscode.workspace.getConfiguration('volar').get('preview.root')!; - const relativePath = path.relative(path.resolve(path.dirname(configFile), root), fileName).replace(/\\/g, '/'); - loadingPanel.webview.html = getWebviewContent(`http://localhost:${port}/__preview${relativePath}`, undefined, 'openExternal'); - } - else if (previewType === PreviewType.Webview) { - loadingPanel.webview.html = getWebviewContent(`http://localhost:${port}`, undefined, 'openSimpleBrowser'); - } - - return port; - - async function webviewEventHandler(message: any) { - switch (message.command) { - case 'openUrl': { - const { url, external } = message.data; - if (external) { - vscode.env.openExternal(vscode.Uri.parse(url)); - } - else { - vscode.commands.executeCommand('simpleBrowser.api.open', url, { preserveFocus: true, viewColumn: _loadingPanel?.viewColumn ?? vscode.ViewColumn.Beside }); - } - _loadingPanel?.dispose(); - break; - } - case 'log': { - const text = message.data; - vscode.window.showInformationMessage(text); - break; - } - case 'warn': { - const text = message.data; - vscode.window.showWarningMessage(text); - break; - } - case 'error': { - const text = message.data; - vscode.window.showErrorMessage(text); - break; - } - } - } - } - - async function handleGoToCode(fileName: string, range: [number, number], cancelToken: { readonly isCancelled: boolean; }) { - - avoidUpdateOnDidChangeActiveTextEditor = true; - - const doc = await vscode.workspace.openTextDocument(fileName); - - if (cancelToken.isCancelled) - return; - - const offset = await getTemplateOffset(doc); - const start = doc.positionAt(range[0] + offset); - const end = doc.positionAt(range[1] + offset); - await vscode.window.showTextDocument(doc, vscode.ViewColumn.One); - - if (cancelToken.isCancelled) - return; - - const editor = vscode.window.activeTextEditor; - if (editor) { - editor.selection = new vscode.Selection(start, end); - editor.revealRange(new vscode.Range(start, end)); - } - } - - async function startPreviewServer(viteDir: string, type: 'vite' | 'nuxt') { - - const port = await getLocalHostAvailablePort(vscode.workspace.getConfiguration('volar').get('preview.port')!); - let script = await vscode.workspace.getConfiguration('volar').get('preview.script.' + (type === 'nuxt' ? 'nuxi' : 'vite')) ?? ''; - - if (script.indexOf('{VITE_BIN}') >= 0) { - script = script.replace('{VITE_BIN}', JSON.stringify(require.resolve('./dist/bin/vite', { paths: [context.extensionPath] }))); - } - if (script.indexOf('{NUXI_BIN}') >= 0) { - script = script.replace('{NUXI_BIN}', JSON.stringify(require.resolve('./dist/bin/nuxi', { paths: [context.extensionPath] }))); - } - if (script.indexOf('{PORT}') >= 0) { - script = script.replace('{PORT}', port.toString()); - } - - const terminal = vscode.window.createTerminal({ - name: 'volar-preview:' + type + ':' + port, - isTransient: true, - }); - terminal.sendText(`cd ${JSON.stringify(viteDir)}`); - terminal.sendText(script); - - return { - port, - terminal, - }; - } - - async function getConfigFile(fileName: path.OsPath, mode: 'vite' | 'nuxt') { - let dir = path.dirname(fileName); - let configFile: path.OsPath | undefined; - while (true) { - const configTs = path.join(dir, mode + '.config.ts' as path.PosixPath); - const configJs = path.join(dir, mode + '.config.js' as path.PosixPath); - if (await fs.exists(vscode.Uri.file(configTs))) { - configFile = configTs; - break; - } - if (await fs.exists(vscode.Uri.file(configJs))) { - configFile = configJs; - break; - } - const upperDir = path.dirname(dir); - if (upperDir === dir) { - break; - } - dir = upperDir; - } - return configFile; - } - - function getWebviewContent(url: string, bg?: string, onLoadEvent?: 'openExternal' | 'openSimpleBrowser') { - - const configs = vscode.workspace.getConfiguration('volar'); - - let html = ` - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - -
- `; - - return html; - } -} diff --git a/packages/vscode-vue-preview/src/utils/fs.ts b/packages/vscode-vue-preview/src/utils/fs.ts deleted file mode 100644 index df972bf30..000000000 --- a/packages/vscode-vue-preview/src/utils/fs.ts +++ /dev/null @@ -1,16 +0,0 @@ -import * as vscode from 'vscode'; - -export async function readFile(uri: vscode.Uri) { - const data = await vscode.workspace.fs.readFile(uri); - return new TextDecoder('utf8').decode(data); -} - -export async function exists(uri: vscode.Uri) { - try { - await vscode.workspace.fs.stat(uri); - return true; - } - catch { - return false; - } -} diff --git a/packages/vscode-vue-preview/src/utils/http.ts b/packages/vscode-vue-preview/src/utils/http.ts deleted file mode 100644 index 479e42d35..000000000 --- a/packages/vscode-vue-preview/src/utils/http.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as http from 'http'; - -export function isLocalHostPortUsing(port: number) { - return new Promise(resolve => { - http.get(`http://localhost:${port}/`, { - headers: { - accept: "*/*", // if not set, always get 404 from vite server - }, - }, res => { - resolve(res.statusCode === 200); - }).on('error', () => resolve(false)).end(); - }); -} - -export async function getLocalHostAvailablePort(port: number) { - if (await isLocalHostPortUsing(port)) { - port++; - } - return port; -} diff --git a/packages/vscode-vue-preview/tsconfig.build.json b/packages/vscode-vue-preview/tsconfig.build.json deleted file mode 100644 index f58d9eb23..000000000 --- a/packages/vscode-vue-preview/tsconfig.build.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "noEmit": false, - "outDir": "out", - "rootDir": "src", - }, - "include": [ - "src", - ], - "references": [ - { - "path": "../preview/tsconfig.build.json" - } - ] -} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d06f7e902..f946a58f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,15 +21,6 @@ importers: vite: 4.1.1_@types+node@18.13.0 vitest: 0.25.8 - packages/preview: - specifiers: - '@types/ws': ^8.5.4 - ws: ^8.12.0 - dependencies: - ws: 8.12.0 - devDependencies: - '@types/ws': 8.5.4 - packages/typescript-vue-plugin: specifiers: '@volar/typescript-faster': 1.2.0-alpha.9 @@ -91,26 +82,6 @@ importers: vscode-languageclient: 8.0.2 vscode-nls: 5.2.0 - packages/vscode-vue-preview: - specifiers: - '@types/vscode': 1.67.0 - '@volar/preview': 1.0.24 - '@volar/vscode-language-client': 1.2.0-alpha.9 - esbuild: 0.15.18 - esbuild-plugin-copy: latest - typesafe-path: ^0.2.2 - vsce: latest - vscode-html-languageservice: ^5.0.4 - devDependencies: - '@types/vscode': 1.67.0 - '@volar/preview': link:../preview - '@volar/vscode-language-client': 1.2.0-alpha.9_@types+vscode@1.67.0 - esbuild: 0.15.18 - esbuild-plugin-copy: 2.0.2_esbuild@0.15.18 - typesafe-path: 0.2.2 - vsce: 2.15.0 - vscode-html-languageservice: 5.0.4 - packages/vue-component-meta: specifiers: '@volar/language-core': 1.2.0-alpha.9 @@ -1131,12 +1102,6 @@ packages: resolution: {integrity: sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g==} dev: true - /@types/ws/8.5.4: - resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} - dependencies: - '@types/node': 18.13.0 - dev: true - /@volar-plugins/css/2.0.0-alpha.2_yhh7mqa563l563iyiu5qxmo6bi: resolution: {integrity: sha512-xKOaWxfNrb28UvGYOOwin2CgJYl2821v6HH1i9sTMlgDup+47T00BhU28tUrV9whYoP5L2+LC5hl7qQGrI7yUw==} peerDependencies: @@ -1360,20 +1325,6 @@ packages: '@volar/language-core': 1.2.0-alpha.9 dev: false - /@volar/vscode-language-client/1.2.0-alpha.9_@types+vscode@1.67.0: - resolution: {integrity: sha512-J/T415nSMh30QgdzhIHsKu0aT+Y0B3OIxWmmevB1N3ZW6F458bk/cZkoum3FNtsHoJSQwINx7iC9gL6z9yptvQ==} - peerDependencies: - '@types/vscode': '*' - vscode-languageclient: '*' - dependencies: - '@types/vscode': 1.67.0 - '@volar/language-server': 1.2.0-alpha.9 - '@volar/shared': 1.2.0-alpha.9 - '@volar/source-map': 1.2.0-alpha.9 - typesafe-path: 0.2.2 - vscode-nls: 5.2.0 - dev: true - /@volar/vscode-language-client/1.2.0-alpha.9_lr35k6ga5htpxuznotx4jg7nl4: resolution: {integrity: sha512-J/T415nSMh30QgdzhIHsKu0aT+Y0B3OIxWmmevB1N3ZW6F458bk/cZkoum3FNtsHoJSQwINx7iC9gL6z9yptvQ==} peerDependencies: @@ -6361,19 +6312,6 @@ packages: dev: false optional: true - /ws/8.12.0: - resolution: {integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - /xml2js/0.4.23: resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} engines: {node: '>=4.0.0'} diff --git a/tsconfig.build.json b/tsconfig.build.json index 51b66a404..db3107a4d 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -6,9 +6,6 @@ { "path": "./packages/vscode-vue/tsconfig.build.json" }, - { - "path": "./packages/vscode-vue-preview/tsconfig.build.json" - }, { "path": "./packages/vscode-typescript-vue-plugin/tsconfig.build.json" }, diff --git a/tsconfig.json b/tsconfig.json index ea8d30555..78a718bd1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,9 +19,6 @@ "noUnusedParameters": true, "baseUrl": "./", "paths": { - "preview": [ - "packages/preview/src" - ], "typescript-vue-plugin": [ "packages/typescript-vue-plugin/src" ],