|
| 1 | +import { html } from 'webjs'; |
| 2 | + |
| 3 | +export const metadata = { title: 'Editor Setup — webjs' }; |
| 4 | + |
| 5 | +export default function EditorSetup() { |
| 6 | + return html` |
| 7 | + <h1>Editor Setup — Neovim & VS Code</h1> |
| 8 | + <p>webjs ships a TypeScript overlay (<code>packages/core/index.d.ts</code> and <code>packages/core/src/component.d.ts</code>) so any editor that speaks the TypeScript Language Server (<code>tsserver</code>) gets full autocomplete, hover documentation, and type-checking for framework APIs — component properties, template results, server actions — with zero build step.</p> |
| 9 | +
|
| 10 | + <h2>Prerequisites</h2> |
| 11 | + <ul> |
| 12 | + <li><strong>Node 23.6+</strong> for native TypeScript type-stripping at runtime.</li> |
| 13 | + <li><strong>TypeScript 5.6+</strong> as a dev dependency in your app (<code>npm i -D typescript</code>). The framework itself has no TS dependency — you only need it for editor intellisense.</li> |
| 14 | + <li>A <code>tsconfig.json</code> in your app. The scaffold generates one.</li> |
| 15 | + </ul> |
| 16 | +
|
| 17 | + <h2><code>tsconfig.json</code> — recommended baseline</h2> |
| 18 | + <p>The scaffold writes this file for you. Manual apps should match:</p> |
| 19 | + <pre>{ |
| 20 | + "compilerOptions": { |
| 21 | + "target": "ES2022", |
| 22 | + "module": "NodeNext", |
| 23 | + "moduleResolution": "NodeNext", |
| 24 | + "lib": ["ES2022", "DOM", "DOM.Iterable"], |
| 25 | + "strict": true, |
| 26 | + "noEmit": true, |
| 27 | + "allowImportingTsExtensions": true, |
| 28 | + "skipLibCheck": true |
| 29 | + } |
| 30 | +}</pre> |
| 31 | + <p>Key points:</p> |
| 32 | + <ul> |
| 33 | + <li><code>moduleResolution: "NodeNext"</code> — required for the framework's <code>exports</code> map to resolve correctly.</li> |
| 34 | + <li><code>allowImportingTsExtensions: true</code> — lets you write <code>import { x } from './foo.ts'</code> in pages and components, matching how webjs actually serves them.</li> |
| 35 | + <li><code>noEmit: true</code> — TypeScript is used for type-checking only; the webjs dev server strips types via Node / esbuild at request time.</li> |
| 36 | + </ul> |
| 37 | +
|
| 38 | + <h2>VS Code</h2> |
| 39 | + <p>Works out of the box. The bundled TypeScript extension picks up your <code>tsconfig.json</code> and the framework's <code>.d.ts</code> overlay automatically. Optional extras:</p> |
| 40 | + <ul> |
| 41 | + <li><strong><a href="https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin" target="_blank">lit-plugin</a></strong> — extends syntax highlighting and offers autocomplete inside <code>html\`\`</code> tagged templates. webjs's template dialect is compatible with Lit's; this plugin works with no configuration.</li> |
| 42 | + <li><strong>Tailwind CSS IntelliSense</strong> — suggests utility classes inside <code>class="..."</code> attributes.</li> |
| 43 | + </ul> |
| 44 | +
|
| 45 | + <h2>Neovim</h2> |
| 46 | + <p>Any TypeScript LSP client will work — the configuration is identical to any other TypeScript project.</p> |
| 47 | +
|
| 48 | + <h3>Option A — <code>nvim-lspconfig</code></h3> |
| 49 | + <pre>-- lua/plugins/tsserver.lua (lazy.nvim) |
| 50 | +return { |
| 51 | + 'neovim/nvim-lspconfig', |
| 52 | + config = function() |
| 53 | + local lspconfig = require('lspconfig') |
| 54 | + lspconfig.ts_ls.setup({ |
| 55 | + settings = { |
| 56 | + typescript = { preferences = { importModuleSpecifier = 'non-relative' } }, |
| 57 | + javascript = { preferences = { importModuleSpecifier = 'non-relative' } }, |
| 58 | + }, |
| 59 | + }) |
| 60 | + end, |
| 61 | +}</pre> |
| 62 | +
|
| 63 | + <h3>Option B — <code>typescript-tools.nvim</code> (recommended)</h3> |
| 64 | + <p>Faster for large projects because it talks to <code>tsserver</code> directly instead of going through <code>tsserver.js</code> over stdin. Setup:</p> |
| 65 | + <pre>return { |
| 66 | + 'pmizio/typescript-tools.nvim', |
| 67 | + dependencies = { 'nvim-lua/plenary.nvim', 'neovim/nvim-lspconfig' }, |
| 68 | + opts = { |
| 69 | + settings = { |
| 70 | + tsserver_file_preferences = { |
| 71 | + importModuleSpecifier = 'non-relative', |
| 72 | + includeCompletionsForModuleExports = true, |
| 73 | + }, |
| 74 | + }, |
| 75 | + }, |
| 76 | +}</pre> |
| 77 | +
|
| 78 | + <h3>Autocomplete + hover bindings</h3> |
| 79 | + <p>Once the LSP is attached (check with <code>:LspInfo</code>), the standard keymaps from your LSP setup apply — commonly:</p> |
| 80 | + <pre>K -- show hover doc (types + JSDoc) |
| 81 | +gd -- go to definition |
| 82 | +gr -- list references |
| 83 | +<leader>ca -- code actions |
| 84 | +<leader>rn -- rename symbol</pre> |
| 85 | +
|
| 86 | + <h3>Completing in <code>html\`\`</code> templates</h3> |
| 87 | + <p>Standard <code>tsserver</code> doesn't look inside tagged template literals. For element/attribute autocomplete inside <code>html\`\`</code> strings, install the <strong>lit-plugin</strong> TypeScript plugin, which works in any tsserver-backed editor (VS Code, Neovim, etc.):</p> |
| 88 | + <pre># In your app root |
| 89 | +npm i -D typescript ts-lit-plugin |
| 90 | +
|
| 91 | +# Add to tsconfig.json compilerOptions: |
| 92 | +"plugins": [{ "name": "ts-lit-plugin", "strict": true }]</pre> |
| 93 | + <p>Neovim users also need to tell <code>tsserver</code> to load plugins from the workspace — <code>nvim-lspconfig</code> does this by default when you have a local <code>node_modules/typescript</code>.</p> |
| 94 | +
|
| 95 | + <h2>Verifying your setup</h2> |
| 96 | + <p>Create <code>components/hello.ts</code>:</p> |
| 97 | + <pre>import { defineComponent, html } from 'webjs'; |
| 98 | +
|
| 99 | +class Hello extends defineComponent({ |
| 100 | + name: { type: String }, |
| 101 | + times: { type: Number }, |
| 102 | +}) { |
| 103 | + static tag = 'hello-card'; |
| 104 | + render() { |
| 105 | + return html\`<p>Hello \${this.name} — \${this.times} times</p>\`; |
| 106 | + } |
| 107 | +} |
| 108 | +Hello.register(import.meta.url);</pre> |
| 109 | +
|
| 110 | + <p>In your editor:</p> |
| 111 | + <ul> |
| 112 | + <li>Hover <code>this.name</code> → should show <code>(property) name: string</code>.</li> |
| 113 | + <li>Hover <code>this.times</code> → should show <code>(property) times: number</code>.</li> |
| 114 | + <li>Type <code>this.</code> → autocomplete lists <code>name</code>, <code>times</code>, <code>setState</code>, <code>requestUpdate</code>, <code>state</code>, etc.</li> |
| 115 | + <li>Change a property usage to the wrong type (e.g. <code>this.name.toFixed(2)</code>) → red underline with <code>Property 'toFixed' does not exist on type 'string'.</code></li> |
| 116 | + </ul> |
| 117 | + <p>If any of these don't work, check <code>:checkhealth</code> (Neovim) or the TypeScript status bar (VS Code) — the most common issue is <code>tsserver</code> picking up a different <code>tsconfig.json</code> than the app's.</p> |
| 118 | +
|
| 119 | + <h2>See also</h2> |
| 120 | + <ul> |
| 121 | + <li><a href="/docs/components">Components</a> — <code>defineComponent</code> API details.</li> |
| 122 | + <li><a href="/docs/typescript">TypeScript</a> — type safety end-to-end.</li> |
| 123 | + <li><a href="/docs/conventions">Conventions</a> — project layout + AI-agent workflow.</li> |
| 124 | + </ul> |
| 125 | + `; |
| 126 | +} |
0 commit comments