Skip to content

Commit 4140b09

Browse files
committed
Clean up issues surrounding static paths, types.
- Removed static path helper. - Fixed issue where locals may change during request handling. - Added missing types. - Fixed issue where body theme color is stale.
1 parent 53a729f commit 4140b09

File tree

11 files changed

+328
-72
lines changed

11 files changed

+328
-72
lines changed

src/browser/pages/vscode.ts

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,100 @@
1+
import { InternalNLSConfiguration } from "../../../lib/vscode/src/vs/base/node/languagePacks"
12
import { getOptions } from "../../common/util"
23

4+
export type Bundles = {
5+
// TODO: Clarify this type.
6+
[name: string]: unknown[]
7+
}
8+
9+
export type BundleCallback = (err: unknown | undefined, messages?: unknown[]) => void | PromiseLike<void>
10+
11+
export interface CodeServerNlsConfiguration extends InternalNLSConfiguration {
12+
loadBundle: (name: string, language: string, cb: BundleCallback) => void
13+
}
14+
15+
export interface CodeServerAmdLoaderConfigurationOptions extends AMDLoader.IConfigurationOptions {
16+
"vs/nls": CodeServerNlsConfiguration
17+
}
18+
319
const options = getOptions()
420

5-
// TODO: Add proper types.
6-
/* eslint-disable @typescript-eslint/no-explicit-any */
21+
const parseNLSConfig = (): CodeServerNlsConfiguration => {
22+
return JSON.parse(document.getElementById("vscode-remote-nls-configuration")!.getAttribute("data-settings")!)
23+
}
24+
25+
const syncTheme = () => {
26+
// First attempt to parse localStorage.
27+
try {
28+
document.body.style.background = JSON.parse(localStorage.getItem("colorThemeData")!).colorMap["editor.background"]
29+
} catch (error) {
30+
// Oh well.
31+
}
32+
33+
// Then, observe the meta theme element for changes.
34+
const themeElement = document.getElementById("monaco-workbench-meta-theme-color") as HTMLMetaElement
35+
36+
const synchronizeTheme = () => {
37+
document.body.style.background = themeElement.content
38+
}
39+
40+
const themeElementObserver = new MutationObserver(synchronizeTheme)
41+
themeElementObserver.observe(themeElement, { attributes: true })
42+
43+
synchronizeTheme()
44+
}
45+
46+
const initializeCodeServerEditor = () => {
47+
syncTheme()
48+
49+
const nlsConfig = parseNLSConfig()
750

8-
let nlsConfig: any
9-
try {
10-
nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration")!.getAttribute("data-settings")!)
1151
if (nlsConfig._resolvedLanguagePackCoreLocation) {
12-
const bundles = Object.create(null)
13-
nlsConfig.loadBundle = (bundle: any, _language: any, cb: any): void => {
52+
const bundles: Bundles = Object.create(null)
53+
54+
nlsConfig.loadBundle = async (bundle, _, cb) => {
1455
const result = bundles[bundle]
56+
1557
if (result) {
1658
return cb(undefined, result)
1759
}
60+
1861
// FIXME: Only works if path separators are /.
1962
const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json"
20-
fetch(`${options.base}/vscode/resource/?path=${encodeURIComponent(path)}`)
21-
.then((response) => response.json())
22-
.then((json) => {
23-
bundles[bundle] = json
24-
cb(undefined, json)
25-
})
26-
.catch(cb)
63+
64+
let body: unknown[]
65+
try {
66+
const response = await fetch(`${options.base}/vscode/resource/?path=${encodeURIComponent(path)}`)
67+
body = await response.json()
68+
} catch (error) {
69+
cb(error)
70+
return
71+
}
72+
73+
bundles[bundle] = body
74+
cb(undefined, body)
2775
}
2876
}
29-
} catch (error) {
30-
/* Probably fine. */
31-
}
3277

33-
;(self.require as any) = {
34-
// Without the full URL VS Code will try to load file://.
35-
baseUrl: `${window.location.origin}${options.csStaticBase}/lib/vscode/out`,
36-
recordStats: true,
37-
paths: {
38-
"vscode-textmate": `../node_modules/vscode-textmate/release/main`,
39-
"vscode-oniguruma": `../node_modules/vscode-oniguruma/release/main`,
40-
xterm: `../node_modules/xterm/lib/xterm.js`,
41-
"xterm-addon-search": `../node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
42-
"xterm-addon-unicode11": `../node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
43-
"xterm-addon-webgl": `../node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
44-
"semver-umd": `../node_modules/semver-umd/lib/semver-umd.js`,
45-
"tas-client-umd": `../node_modules/tas-client-umd/lib/tas-client-umd.js`,
46-
"iconv-lite-umd": `../node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
47-
jschardet: `../node_modules/jschardet/dist/jschardet.min.js`,
48-
},
49-
"vs/nls": nlsConfig,
50-
}
78+
const amdLoaderConfig: CodeServerAmdLoaderConfigurationOptions = {
79+
// Without the full URL VS Code will try to load file://.
80+
baseUrl: `${window.location.origin}${options.base}/static/lib/vscode/out`,
81+
recordStats: true,
82+
paths: {
83+
"vscode-textmate": `../node_modules/vscode-textmate/release/main`,
84+
"vscode-oniguruma": `../node_modules/vscode-oniguruma/release/main`,
85+
xterm: `../node_modules/xterm/lib/xterm.js`,
86+
"xterm-addon-search": `../node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
87+
"xterm-addon-unicode11": `../node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
88+
"xterm-addon-webgl": `../node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
89+
"semver-umd": `../node_modules/semver-umd/lib/semver-umd.js`,
90+
"tas-client-umd": `../node_modules/tas-client-umd/lib/tas-client-umd.js`,
91+
"iconv-lite-umd": `../node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
92+
jschardet: `../node_modules/jschardet/dist/jschardet.min.js`,
93+
},
94+
"vs/nls": nlsConfig,
95+
}
5196

52-
try {
53-
document.body.style.background = JSON.parse(localStorage.getItem("colorThemeData")!).colorMap["editor.background"]
54-
} catch (error) {
55-
// Oh well.
97+
;(self.require as any) = amdLoaderConfig
5698
}
99+
100+
initializeCodeServerEditor()

src/browser/views/error.handlebars

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
content="style-src 'self'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
1212
/>
1313
<title>{{ERROR_TITLE}} — Code Server</title>
14-
<link rel="icon" href="{{assetPath csStaticBase '/media/favicon.ico'}}" type="image/x-icon" />
14+
<link rel="icon" href="{{assetPath base '/static/media/favicon.ico'}}" type="image/x-icon" />
1515
<link rel="manifest" href="{{assetPath base '/code-server.webmanifest'}}" crossorigin="use-credentials" />
16-
<link rel="apple-touch-icon" href="{{assetPath csStaticBase '/media/pwa-icon-384.png'}}" />
17-
<link href="{{assetPath csStaticBase '/register.css'}}" rel="stylesheet" />
16+
<link rel="apple-touch-icon" href="{{assetPath base '/static/media/pwa-icon-384.png'}}" />
17+
<link href="{{assetPath base '/static/register.css'}}" rel="stylesheet" />
1818
<meta id="coder-options" data-settings="{{{json coderOptions}}}" />
1919
</head>
2020
<body>

src/browser/views/login.handlebars

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
/>
1313
<title>Login — Code Server</title>
1414

15-
<link rel="icon" href="{{assetPath csStaticBase '/media/favicon.ico'}}" type="image/x-icon" />
15+
<link rel="icon" href="{{assetPath base '/static/media/favicon.ico'}}" type="image/x-icon" />
1616
<link rel="manifest" href="{{assetPath base '/code-server.webmanifest'}}" crossorigin="use-credentials" />
17-
<link rel="apple-touch-icon" href="{{assetPath csStaticBase '/src/browser/media/pwa-icon-384.png'}}" />
17+
<link rel="apple-touch-icon" href="{{assetPath base '/static/src/browser/media/pwa-icon-384.png'}}" />
1818
<link href="{{assetPath base '/register.css'}}" rel="stylesheet" />
1919
<meta id="coder-options" data-settings="{{{json coderOptions}}}" />
2020
</head>

src/browser/views/vscode.handlebars

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,26 @@
1818

1919
<!-- Workbench Configuration -->
2020
<meta id="vscode-workbench-web-configuration" data-settings="{{{json workbenchOptions.workbenchWebConfiguration}}}" />
21-
21+
<meta id="monaco-workbench-meta-theme-color" name="theme-color" content="" />
2222
<!-- Workarounds/Hacks (remote user data uri) -->
2323
<meta id="vscode-remote-user-data-uri" data-settings="{{{json workbenchOptions.remoteUserDataUri}}}" />
2424
<meta id="vscode-remote-product-configuration" data-settings="{{{json workbenchOptions.productConfiguration}}}" />
2525
<meta id="vscode-remote-nls-configuration" data-settings="{{{json workbenchOptions.nlsConfiguration}}}" />
2626

2727
<!-- Workbench Icon/Manifest/CSS -->
28-
<link rel="icon" href="{{assetPath csStaticBase '/src/browser/media/favicon.ico'}}" type="image/x-icon" />
28+
<link rel="icon" href="{{assetPath base '/static/media/favicon.ico'}}" type="image/x-icon" />
2929
<link rel="manifest" href="./code-server.webmanifest" crossorigin="use-credentials" />
3030

3131
{{#if (prod)}}
32-
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{assetPath csStaticBase '/lib/vscode/out/vs/workbench/workbench.web.api.css'}}">
32+
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{assetPath base '/static/lib/vscode/out/vs/workbench/workbench.web.api.css'}}">
3333
{{/if}}
3434

35-
<link rel="apple-touch-icon" href="{{assetPath csStaticBase '/src/browser/media/pwa-icon-384.png'}}" />
35+
<link rel="apple-touch-icon" href="{{assetPath base '/static/src/browser/media/pwa-icon-384.png'}}" />
3636
<meta name="apple-mobile-web-app-capable" content="yes" />
3737

3838
<!-- Prefetch to avoid waterfall -->
3939
{{#if (prod)}}
40-
<link rel="prefetch" href="{{assetPath csStaticBase '/lib/vscode/node_modules/semver-umd/lib/semver-umd.js'}}">
40+
<link rel="prefetch" href="{{assetPath base '/static/lib/vscode/node_modules/semver-umd/lib/semver-umd.js'}}">
4141
{{/if}}
4242

4343
<meta id="coder-options" data-settings="{{{json coderOptions}}}" />

src/common/util.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { logger, field } from "@coder/logger"
22

33
export interface Options {
44
base: string
5-
csStaticBase: string
65
logLevel: number
76
}
87

@@ -82,7 +81,6 @@ export const getOptions = <T extends Options>(): T => {
8281
logger.level = options.logLevel
8382

8483
options.base = resolveBase(options.base)
85-
options.csStaticBase = resolveBase(options.csStaticBase)
8684

8785
logger.debug("got options", field("options", options))
8886

src/node/http.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,11 @@ export interface CommonTemplateVars extends Options {
2121

2222
export const commonTemplateVars = <T extends Options>(
2323
req: express.Request,
24-
extraOpts?: Omit<T, "base" | "csStaticBase" | "logLevel">,
24+
extraOpts?: Omit<T, "base" | "logLevel">,
2525
): CommonTemplateVars => {
2626
const base = relativeRoot(req)
27-
const csStaticBase = base + "/static/"
2827
const coderOptions: Options = {
2928
base,
30-
csStaticBase,
3129
logLevel: logger.level,
3230
...extraOpts,
3331
}
@@ -38,16 +36,6 @@ export const commonTemplateVars = <T extends Options>(
3836
}
3937
}
4038

41-
/**
42-
* Injects variables into template scope.
43-
*/
44-
export const templateMiddleware = (locals: express.Application["locals"]): express.RequestHandler => {
45-
return (req, _, next) => {
46-
Object.assign(locals, commonTemplateVars(req))
47-
next()
48-
}
49-
}
50-
5139
/**
5240
* Throw an error if not authorized.
5341
*/

src/node/routes/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { plural } from "../../common/util"
1111
import { AuthType, DefaultedArgs } from "../cli"
1212
import { rootPath } from "../constants"
1313
import { Heart } from "../heart"
14-
import { templateMiddleware } from "../http"
14+
import { commonTemplateVars } from "../http"
1515
import { loadPlugins } from "../plugin"
1616
import * as domainProxy from "../proxy"
1717
import { getMediaMime, paths } from "../util"
@@ -55,7 +55,6 @@ export const register = async (app: Express, server: http.Server, args: Defaulte
5555
app.use(cookieParser())
5656
app.use(bodyParser.json())
5757
app.use(bodyParser.urlencoded({ extended: true }))
58-
app.use(templateMiddleware(app.locals))
5958

6059
server.on("upgrade", () => {
6160
heart.beat()
@@ -85,10 +84,10 @@ export const register = async (app: Express, server: http.Server, args: Defaulte
8584
return next()
8685
})
8786

88-
app.use("/", _static.router)
8987
app.use("/", domainProxy.router)
9088
app.use("/", vscode.router)
9189
app.use("/", manifest.router)
90+
app.use("/", _static.router)
9291

9392
app.use("/healthz", health.router)
9493
if (args.auth === AuthType.Password) {
@@ -113,6 +112,7 @@ export const register = async (app: Express, server: http.Server, args: Defaulte
113112

114113
try {
115114
res.status(status).render("error", {
115+
...commonTemplateVars(req),
116116
HOME_PATH: (typeof req.query.to === "string" && req.query.to) || "/",
117117
ERROR_TITLE: status,
118118
ERROR_HEADER: status,

src/node/routes/login.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Router, ErrorRequestHandler } from "express"
22
import { RateLimiter as Limiter } from "limiter"
33
import safeCompare from "safe-compare"
4-
import { authenticated, getCookieDomain, redirect } from "../http"
4+
import { authenticated, commonTemplateVars, getCookieDomain, redirect } from "../http"
55
import { hash, humanPath } from "../util"
66

77
enum Cookie {
@@ -28,6 +28,7 @@ const rootHandler: ErrorRequestHandler = async (error: Error | undefined, req, r
2828
: `Check the config file at ${humanPath(req.args.config)} for the password.`
2929

3030
res.render("login", {
31+
...commonTemplateVars(req),
3132
PASSWORD_MSG: passwordMsg,
3233
ERROR: error?.message || "",
3334
})

src/node/routes/manifest.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ export const router = Router()
66

77
const iconSizes = [96, 128, 192, 256, 384, 512]
88

9-
export const createWebManifest = ({ base, csStaticBase }: CommonTemplateVars) => {
9+
export const createWebManifest = ({ base }: CommonTemplateVars) => {
1010
const icons = iconSizes.map((iconSize) => ({
11-
src: normalize(`${csStaticBase}/media/pwa-icon-${iconSize}.png`),
11+
src: normalize(`${base}/static/media/pwa-icon-${iconSize}.png`),
1212
type: "image/png",
1313
sizes: `${iconSize}x${iconSize}`,
1414
}))
@@ -27,5 +27,5 @@ export const createWebManifest = ({ base, csStaticBase }: CommonTemplateVars) =>
2727
router.get("/code-server.webmanifest", (req, res) => {
2828
const webManifest = commonTemplateVars(req)
2929

30-
res.contentType("application/manifest+json").json(webManifest)
30+
res.contentType("application/manifest+json").json(createWebManifest(webManifest))
3131
})

src/node/routes/vscode.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { promises as fs } from "fs"
44
import * as path from "path"
55
import { WorkbenchOptions } from "../../../lib/vscode/src/vs/server/ipc"
66
import { commit, version } from "../constants"
7-
import { authenticated, ensureAuthenticated, redirect } from "../http"
7+
import { authenticated, commonTemplateVars, ensureAuthenticated, redirect } from "../http"
88
import { getMediaMime, pathToFsPath } from "../util"
99
import { VscodeProvider } from "../vscode"
1010

@@ -37,6 +37,7 @@ router.get("/", async (req, res) => {
3737
workbenchOptions.productConfiguration.codeServerVersion = version
3838

3939
res.render("vscode", {
40+
...commonTemplateVars(req),
4041
disableTelemetry: !!req.args["disable-telemetry"],
4142
workbenchOptions,
4243
})

0 commit comments

Comments
 (0)