tomjs / vite-plugin-vscode

用 vue/react 来开发 vscode extension webview ,支持 esm 和 cjs。Use vue/react to develop vscode extension webview, supporting esm and cjs.
MIT License
41 stars 6 forks source link

支持导入html文件 #2

Closed frg2089 closed 10 months ago

frg2089 commented 10 months ago

使能够在vscode扩展的代码中能够导入html内容

项目中已经包含了一个或多个html文件 能否实现直接导入html文件内容而不是在代码中内联html

直接用import的话可能会使热重载失效 提供一个工具函数也可以

这是我之前写的导入html内容的esbuild插件

插件 ```typescript import * as esbuild from 'esbuild' import * as fs from 'node:fs' import * as path from 'node:path' import * as crypto from 'node:crypto' import * as url from 'node:url' interface HtmlPluginData { resolveDir: string fileName: string fullPath: string } export const htmlCompiler = (): esbuild.Plugin => { return { name: 'esbuild-plugin-html', setup: build => { // 处理 *.vue 文件中的 script build.onResolve({ filter: /\.html$/ }, async args => { const filePath = args.path const fileName = path.basename(filePath) const fullPath = path.resolve(args.resolveDir, filePath) return { path: args.path, namespace: 'vscode-html', pluginData: { ...args.pluginData, resolveDir: args.resolveDir, fileName, fullPath, } as HtmlPluginData, } }) build.onLoad( { filter: /\.html$/, namespace: 'vscode-html' }, async args => { const data = args.pluginData as HtmlPluginData const content = await fs.promises.readFile(data.fullPath, 'utf8') const code = new Array() code.push('export default (data) =>') code.push(` Object.entries(data).reduce(`) code.push(` (html, [property, value]) =>`) code.push( ' html.replaceAll(`\\$\\{\\{${property}\\}\\}`, value),', ) code.push(` ${JSON.stringify(content)},`) code.push(' )') const contents = code.join('\n') return { contents, resolveDir: data.resolveDir, loader: 'js', watchFiles: [args.path], } }, ) }, } } ```
示例 ```html Document
``` ```typescript import html from './pages/ShpViewer.html' // ... const stylesUri = this.buildUri(`index.css`) const scriptUri = this.buildUri(`index.js`) const nonce = crypto.randomUUID() const csp = [ `default-src ${this.panel.webview.cspSource} data: blob:`, `style-src ${this.panel.webview.cspSource} 'unsafe-inline'`, `script-src ${this.panel.webview.cspSource} blob: 'unsafe-eval' 'nonce-${nonce}'`, ].join('; ') + ';' this.panel.webview.html = html({ stylesUri: stylesUri, scriptUri: scriptUri, nonce: nonce, csp: csp, }) ```
tomgao365 commented 10 months ago

@frg2089 ,😆根据你的建议,做了个调整,你试试是否满足你的需求。 vite build 时,根据 index.html 生成 webview 的 html 代码,也支持多页面。

https://github.com/tomjs/vite-plugin-vscode/blob/48702a748ba8ec310bb7f2dbd744ce76d63b5343/examples/vue-import/vite.config.ts#L24-L34

https://github.com/tomjs/vite-plugin-vscode/blob/397beebb14bc12fce8bb3e8c3bdaacb5a041a477/examples/vue-import/extension/views/helper.ts#L13-L25

frg2089 commented 10 months ago

辛苦了 我实际开发的过程中发现 多个html文件似乎多余 因为到最后都是只挂载一个vue

所以 模板什么的只要一个就好了

或许我需要的是这样的东西

当运行在dev模式下

process.env.VITE_DEV_SERVER_URL + '?src=' + encodeURIComponent(path);

使用build构建后 读/dist/webview/index.html文件然后稍作修改

在意识到这点之前的我的解决方案 ```typescript import * as crypto from 'node:crypto' import * as fs from 'node:fs/promises' import * as vscode from 'vscode' import * as htmlparser2 from 'htmlparser2' import render from 'dom-serializer' import * as selector from 'css-select' /** * * @param option 设置 * @returns */ export const getHtml = async (option: { enterPoint: string extensionUri: vscode.Uri cspSource: string /** 用到的依赖 比如 pixi.js */ dependencies?: string[] }) => { if (process.env.VITE_DEV_SERVER_URL) { console.log( 'VITE_DEV_SERVER_URL:', process.env.VITE_DEV_SERVER_URL + option.enterPoint, ) return __getWebviewHtml__( process.env.VITE_DEV_SERVER_URL + option.enterPoint, ) } else { const { enterPoint, extensionUri, cspSource, dependencies = [] } = option const nonce = crypto.randomUUID() const base = vscode.Uri.joinPath(extensionUri, 'dist', 'webview') const assets = vscode.Uri.joinPath(base, 'assets') const csp = [ `default-src ${cspSource} data: blob:`, `style-src ${cspSource} 'unsafe-inline'`, `script-src ${cspSource} blob: 'unsafe-eval' 'nonce-${nonce}'`, ].join('; ') + ';' const page = vscode.Uri.joinPath(base, enterPoint + '.html') const css = vscode.Uri.joinPath(assets, enterPoint + '.css') const jss = dependencies.map(i => vscode.Uri.joinPath(assets, i + '.js')) jss.push(vscode.Uri.joinPath(assets, enterPoint + '.js')) const content = await fs.readFile(page.fsPath, { encoding: 'utf-8' }) const doc = htmlparser2.parseDocument(content) const head = selector.selectOne('head', doc) ;[ ``, ``, ].forEach(i => head.childNodes.push(htmlparser2.parseDocument(i))) const body = selector.selectOne('body', doc) // 清除 script body.childNodes = body.childNodes.filter( i => i.type != htmlparser2.ElementType.Script, ) jss.map(i => body.childNodes.push( htmlparser2.parseDocument( ``, ), ), ) return render(doc) } } ```
tomgao365 commented 10 months ago

👌我最初dev阶段,也考虑了类似的思路。是用 vite build --watch,然后再用 fs.read 读取文本内容去更新 html,不过每次修改后就等于页面强刷了,没了热更新。