-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Virtual File Systems & Shopify Liquid VS Code extension for Web #529
Conversation
}; | ||
|
||
const reader = new BrowserMessageReader(worker); | ||
const writer = new BrowserMessageWriter(worker); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I learned by looking at examples that there was an easier way :)
@@ -40,6 +40,7 @@ | |||
"dev:build": "webpack --mode development", | |||
"dev:syntax": "yarn --cwd ./syntaxes dev", | |||
"dev:watch": "webpack --mode development --watch", | |||
"dev:web": "yarn build && vscode-test-web --permission=clipboard-read --permission=clipboard-write --browserType=chromium --extensionDevelopmentPath=.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vscode-test-web is the one that lets you run chrome and have vscode run in it with your extension loaded. It was a real breeze ngl!
@@ -83,7 +85,8 @@ | |||
"activationEvents": [ | |||
"workspaceContains:**/.theme-check.yml" | |||
], | |||
"main": "./dist/extension.js", | |||
"main": "./dist/node/extension.js", | |||
"browser": "./dist/browser/extension.js", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Major difference is here: We have a different build for web that uses theme-language-server-browser
instead of theme-language-server-node
"messages", | ||
"verbose" | ||
] | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added that stuff in there because I was tired of not having code completion in settings.json to enable the LSP logging
bdbbc56
to
35b07d1
Compare
7c5b372
to
71d5086
Compare
/** | ||
* The AbstractFileSystem interface is used to abstract file system operations. | ||
* | ||
* This way, the Theme Check library can be used in different environments, | ||
* such as the browser, node.js or VS Code (which works with local files, remote | ||
* files and on the web) | ||
*/ | ||
export interface AbstractFileSystem { | ||
stat(uri: string): Promise<FileStat>; | ||
readFile(uri: string): Promise<string>; | ||
readDirectory(uri: string): Promise<FileTuple[]>; | ||
} | ||
|
||
export enum FileType { | ||
Unknown = 0, | ||
File = 1, | ||
Directory = 2, | ||
SymbolicLink = 64, | ||
} | ||
|
||
export interface FileStat { | ||
type: FileType; | ||
size: number; | ||
} | ||
|
||
/** A vscode-uri string */ | ||
export type UriString = string; | ||
|
||
export type FileTuple = [uri: UriString, fileType: FileType]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably the most important file in this large diff.
fileExists, | ||
fileSize, | ||
filesForURI, | ||
findRootURI: findConfigurationRootURI, | ||
getDefaultLocaleFactory, | ||
getDefaultTranslationsFactory, | ||
getDefaultSchemaLocaleFactory, | ||
getDefaultSchemaTranslationsFactory, | ||
getThemeSettingsSchemaForRootURI, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:)
fileExists, | ||
fileSize, | ||
findRootURI: findConfigurationRootURI, | ||
getDefaultLocaleFactory, | ||
getDefaultTranslationsFactory, | ||
getDefaultSchemaLocaleFactory, | ||
getDefaultSchemaTranslationsFactory, | ||
fs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:)
@@ -48,7 +51,7 @@ export interface RequiredDependencies { | |||
* @param uri - a file path | |||
* @returns {Promise<Config>} | |||
*/ | |||
loadConfig(uri: URI): Promise<Config>; | |||
loadConfig(uri: URI, fileExists: (uri: string) => Promise<boolean>): Promise<Config>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the fileExists here is a performance improvement. Wanted loadConfig
to use findRoot
and that thing depends on fileExists
which should be the CachedFileSystem, not the raw one.
{ scheme: 'file', language: 'liquid' }, | ||
{ scheme: 'file', language: 'plaintext' }, | ||
{ scheme: 'file', language: 'html' }, | ||
{ scheme: 'file', language: 'javascript' }, | ||
{ scheme: 'file', language: 'css' }, | ||
{ scheme: 'file', language: 'scss' }, | ||
{ scheme: 'file', language: 'json' }, | ||
{ scheme: 'file', language: 'jsonc' }, | ||
{ language: 'liquid' }, | ||
{ language: 'plaintext' }, | ||
{ language: 'html' }, | ||
{ language: 'javascript' }, | ||
{ language: 'css' }, | ||
{ language: 'scss' }, | ||
{ language: 'json' }, | ||
{ language: 'jsonc' }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This thing took me a while to figure out since I wrote this 3 years ago. We need to remove scheme
in order for completion requests from vscode-vfs://
URIs to trigger.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comes with the drawback of showing Document Link errors in git://
URIs. (which I believe are git diff URIs)...
libraryTarget: 'var', | ||
library: 'serverExportVar', | ||
devtoolModuleFilenameTemplate: '../../[resource-path]', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only reason I need 2x a config that should look like one is because of this difference here. The worker has to be "import-less", but the extension needs a require('vscode')
call in the output that gets shimmed.
3bc7078
to
3919133
Compare
We still have an optiomal dependency that is otherwise implemented by a naive implementation (for CLI use cases), but in the language server we prefer the buffer over the file in the file system... Which makes me think we could get rid of that by actually making that logic part of the getTranslationsFactory directly. Prefer theme files over fs.
All that logic didn't need to be in the language server. This makes the dep injection easier too because we no longer have this upstream concern.
Replace with AbstractFileSystem-based implementation
Replace with abstract-file-system-based implementation TODO make that shit faster. Seems highlighy unoptimized.
Replace with abstract-file-system-based implementation in common code.
- Adds support for VS Code for Web - Adds support for remote files
You don't need to query VS Code _every time_ the user types something for the same imformation. That's rather slow! We'll invalidate the relevant caches when files are saved/deleted/created/renamed.
Made to demo what it's like to use a VirtualFileSystem in a non-vscode environment.
0a58241
to
6e2b36e
Compare
client.onRequest('fs/readDirectory', async (uriString: string): Promise<FileTuple[]> => { | ||
const results = await workspace.fs.readDirectory(Uri.parse(uriString)); | ||
return results.map(([name, type]) => [path.join(uriString, name), type]); | ||
}); | ||
|
||
const textDecoder = new TextDecoder(); | ||
client.onRequest('fs/readFile', async (uriString: string): Promise<string> => { | ||
const bytes = await workspace.fs.readFile(Uri.parse(uriString)); | ||
return textDecoder.decode(bytes); | ||
}); | ||
|
||
client.onRequest('fs/stat', async (uriString: string): Promise<FileStat> => { | ||
return workspace.fs.stat(Uri.parse(uriString)); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should have highlighted this code in the pairing session as well. This is the client code that handles the VsCodeFileSystem LSP requests. @aswamy @graygilmore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the one that calls the VS Code FileSystem API
vscode.workspace.fs.readFile() // returns a UInt8Array (bytes)
// AbstractFileSystem.readFile is Promise<string>, this is why we do textDecoder.decode(bytes) on the result.
packages/theme-language-server-common/src/diagnostics/runChecks.ts
Outdated
Show resolved
Hide resolved
I also removed the double reporting of parser errors. Now that theme check is on the same parser as the prettier plugin, there's no point in showing the error message reported from two different sources. Fixes #533
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry took some time, but we should be good. Minor comments + concerns, but nothing blocking atm.
Tophat complete:
- Able to run VScode web, able to edit files, save it
- Able to run VScode web in "sandbox" mode (vscode-test-web), able to edit files - does not persist file as expected
- Able to run desktop VSCode with web extension, able to edit files, save it
- Able to run Codemirror Client, able to edit files, save it
.theme-check.yml
file in the wrong directory. It could be one of the rootPath functions are messed up because i saw this in all VScode scenarios above. However, Node extension had it as a thrown error, while Browser Extension had it as a info-message.
@@ -23,6 +23,7 @@ | |||
"build": "yarn workspaces run build", | |||
"build:ci": "yarn workspaces run build:ci", | |||
"build:ts": "yarn workspaces run build:ts", | |||
"dev:web": "yarn --cwd packages/vscode-extension dev:web", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
glob
package fails if you don't have node v20-22. Could we add an .nvmrc to have v22
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Durr I have a .nvmrc
but I git ignored/excluded it? Yeah def should do
packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.spec.ts
Outdated
Show resolved
Hide resolved
packages/theme-check-common/src/checks/translation-key-exists/index.spec.ts
Outdated
Show resolved
Hide resolved
7b951fc
to
6ef16d6
Compare
What are you adding in this PR?
vscode-extension
:browser
entry in ourpackage.json
src
folder has been split intonode
,common
andbrowser
foldersbrowser
module starts the language server in a Web Workernode
module starts the language server in a subprocesstheme-check-*
, andtheme-language-server-*
:AbsolutePath
concerns withUri
s.Dependencies
with a singlefs: AbstractFileSystem
dependencyfs
NodeFileSystem
is available (and used by default)NodeFileSystem
is available (and used by default)VsCodeFileSystem
is availablefs/readFile
-> a TextDecodedvscode.workspace.fs.readFile(uri)
fs/readDirectory
->vscode.workspace.fs.readDirectory(uri)
fs/stat
->vscode.workspace.fs.stat(uri)
node
, the same happens but short circuits to theNodeFileSystem
forfile:///
URIs.codemirror-language-client
's playground implements a mock "MainThreadFileSystem" that we could use as inspiration for online-store-webDemo
vscode-for-web-vfs.mp4
Top-hatting
Debugging in Chromium VS Code for Web
The "true" E2E way. Demo worthy version of "showing it works in browser"
vscode-for-web-vfs-2.mp4
Debugging in the Desktop app
A faster, debuggable way that runs the browser extension in the desktop app. This disables all the Node APIs but it lets you debug the code.
vscode-for-web-vfs-desktop.mp4
Debugging the CodeMirror Language client
(Not new, but you should know that this flow is also updated to virtual file systems).
vscode-for-web-vfs-codemirror.mp4
What's next? Any followup issues?
loadConfig
work in-browserWhat did you learn?
BrowserMessageReader(worker)
andBrowserMessageWriter(worker)
.vscode.workspace.fs
is pretty cool. It does a pretty clever the URIScheme -> FileSystemProvider mapping that makes it so we could eventually have a "ShopifyBackendFileSystem" that would write directly to the storefront.Before you deploy
changeset