Skip to content

Commit

Permalink
put load_component back where it used to be so that file system watch…
Browse files Browse the repository at this point in the history
…er doesn't depend on Vite
  • Loading branch information
benmccann committed Dec 30, 2021
1 parent 5c63f33 commit 7b99623
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 93 deletions.
8 changes: 3 additions & 5 deletions packages/kit/src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ prog

try {
const cwd = process.cwd();
const watcher = await dev({ port, host, https, config, cwd });
const { watcher, vite } = await dev({ port, host, https, config, cwd });

watcher.on('stdout', (data) => {
process.stdout.write(data);
Expand All @@ -102,13 +102,11 @@ prog
process.stderr.write(data);
});

if (!watcher.vite || !watcher.vite.httpServer) {
if (!vite || !vite.httpServer) {
throw Error('Could not find server');
}
// we never start the server on a socket path, so address will be of type AddressInfo
const address_info = /** @type {import('net').AddressInfo} */ (
watcher.vite.httpServer.address()
);
const address_info = /** @type {import('net').AddressInfo} */ (vite.httpServer.address());

const vite_config = config.kit.vite();

Expand Down
142 changes: 68 additions & 74 deletions packages/kit/src/core/dev/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,25 @@ export async function dev(opts) {
merged_config.server.port = opts.port;
}

watcher.vite = await vite.createServer(merged_config);
await watcher.vite.listen(opts.port);
const vite_server = await vite.createServer(merged_config);
await vite_server.listen(opts.port);

return watcher;
let closed = false;
process.on('exit', () => {
if (!vite_server || !watcher.cheapwatch) {
throw new Error('Cannot close server before it is initialized');
}

if (closed) return;
closed = true;

vite_server.close();

// TODO: can we create the watcher in the plugin and close it in closeBundle
watcher.cheapwatch.close();
});

return { watcher, vite: vite_server };
}

class Watcher extends EventEmitter {
Expand All @@ -126,15 +141,6 @@ class Watcher extends EventEmitter {

/** @type {import('types/config').ValidatedConfig} */
this.config = config;

/**
* @type {vite.ViteDevServer | undefined}
*/
this.vite;

process.on('exit', () => {
this.close();
});
}

async init() {
Expand Down Expand Up @@ -186,51 +192,7 @@ class Watcher extends EventEmitter {
css: [],
js: []
},
nodes: manifest_data.components.map((id) => {
return async () => {
const url = `/${id}`;

if (!this.vite) throw new Error('Vite server has not been initialized');

const module = /** @type {SSRComponent} */ (await this.vite.ssrLoadModule(url));
const node = await this.vite.moduleGraph.getModuleByUrl(url);

if (!node) throw new Error(`Could not find node for ${url}`);

const deps = new Set();
find_deps(node, deps);

const styles = new Set();

for (const dep of deps) {
const parsed = new URL(dep.url, 'http://localhost/');
const query = parsed.searchParams;

// TODO what about .scss files, etc?
if (
dep.file.endsWith('.css') ||
(query.has('svelte') && query.get('type') === 'style')
) {
try {
const mod = await this.vite.ssrLoadModule(dep.url);
styles.add(mod.default);
} catch {
// this can happen with dynamically imported modules, I think
// because the Vite module graph doesn't distinguish between
// static and dynamic imports? TODO investigate, submit fix
}
}
}

return {
module,
entry: url.endsWith('.svelte') ? url : url + '?import',
css: [],
js: [],
styles: Array.from(styles)
};
};
}),
nodes: manifest_data.components,
routes: manifest_data.routes.map((route) => {
if (route.type === 'page') {
return {
Expand All @@ -246,28 +208,12 @@ class Watcher extends EventEmitter {
type: 'endpoint',
pattern: route.pattern,
params: get_params(route.params),
load: async () => {
if (!this.vite) throw new Error('Vite server has not been initialized');
const url = path.resolve(this.cwd, route.file);
return await this.vite.ssrLoadModule(url);
}
file: route.file
};
})
}
};
}

close() {
if (!this.vite || !this.cheapwatch) {
throw new Error('Cannot close server before it is initialized');
}

if (this.closed) return;
this.closed = true;

this.vite.close();
this.cheapwatch.close();
}
}

/**
Expand Down Expand Up @@ -418,6 +364,54 @@ async function create_plugin(opts, dir, get_manifest) {
},
hooks,
hydrate: config.kit.hydrate,
load_component: async (id) => {
const url = `/${id}`;

if (!vite) throw new Error('Vite server has not been initialized');

const module = /** @type {SSRComponent} */ (await vite.ssrLoadModule(url));
const node = await vite.moduleGraph.getModuleByUrl(url);

if (!node) throw new Error(`Could not find node for ${url}`);

const deps = new Set();
find_deps(node, deps);

const styles = new Set();

for (const dep of deps) {
const parsed = new URL(dep.url, 'http://localhost/');
const query = parsed.searchParams;

// TODO what about .scss files, etc?
if (
dep.file.endsWith('.css') ||
(query.has('svelte') && query.get('type') === 'style')
) {
try {
const mod = await vite.ssrLoadModule(dep.url);
styles.add(mod.default);
} catch {
// this can happen with dynamically imported modules, I think
// because the Vite module graph doesn't distinguish between
// static and dynamic imports? TODO investigate, submit fix
}
}
}

return {
module,
entry: url.endsWith('.svelte') ? url : url + '?import',
css: [],
js: [],
styles: Array.from(styles)
};
},
load_endpoint: async (file) => {
if (!vite) throw new Error('Vite server has not been initialized');
const url = path.resolve(opts.cwd, file);
return await vite.ssrLoadModule(url);
},
manifest: get_manifest(),
paths: {
base: config.kit.paths.base,
Expand Down
5 changes: 3 additions & 2 deletions packages/kit/src/runtime/server/endpoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ function is_content_type_textual(content_type) {
* @param {import('types/hooks').ServerRequest} request
* @param {import('types/internal').SSREndpoint} route
* @param {RegExpExecArray} match
* @param {import('types/internal').SSRRenderOptions} options
* @returns {Promise<import('types/hooks').ServerResponse | undefined>}
*/
export async function render_endpoint(request, route, match) {
const mod = await route.load();
export async function render_endpoint(request, route, match, options) {
const mod = await options.load_endpoint(route.file);

/** @type {import('types/endpoint').RequestHandler} */
const handler = mod[request.method.toLowerCase().replace('delete', 'del')]; // 'delete' is a reserved word
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/runtime/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export async function respond(incoming, options, state = {}) {

const response =
route.type === 'endpoint'
? await render_endpoint(request, route, match)
? await render_endpoint(request, route, match, options)
: await render_page(request, route, match, options, state);

if (response) {
Expand Down
11 changes: 9 additions & 2 deletions packages/kit/src/runtime/server/page/respond.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ export async function respond(opts) {

try {
nodes = await Promise.all(
route.a.map((n) => options.manifest._.nodes[n] && options.manifest._.nodes[n]())
route.a.map((n) => {
const node = options.manifest._.nodes[n];
if (node) {
return options.load_component(node);
}
})
);
} catch (err) {
const error = coalesce_to_error(err);
Expand Down Expand Up @@ -128,7 +133,9 @@ export async function respond(opts) {
if (error) {
while (i--) {
if (route.b[i]) {
const error_node = await options.manifest._.nodes[route.b[i]]();
const error_node = await options.load_component(
/** @type {string} */ (options.manifest._.nodes[route.b[i]])
);

/** @type {Loaded} */
let node_loaded;
Expand Down
8 changes: 6 additions & 2 deletions packages/kit/src/runtime/server/page/respond_with_error.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ import { coalesce_to_error } from '../../../utils/error.js';
* }} opts
*/
export async function respond_with_error({ request, options, state, $session, status, error }) {
const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
const default_layout = await options.load_component(
/** @type {string} */ (options.manifest._.nodes[0]) // 0 is always the root layout
);
const default_error = await options.load_component(
/** @type {string} */ (options.manifest._.nodes[1]) // 1 is always the root error
);

const page = {
origin: request.origin,
Expand Down
4 changes: 2 additions & 2 deletions packages/kit/types/app.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ReadOnlyFormData, RequestHeaders } from './helper';
import { ServerResponse } from './hooks';
import { PrerenderOptions, SSRNodeLoader, SSRRoute } from './internal';
import { PrerenderOptions, SSRRoute } from './internal';

export class App {
constructor(manifest: SSRManifest);
Expand Down Expand Up @@ -40,7 +40,7 @@ export interface SSRManifest {
js: string[];
css: string[];
};
nodes: SSRNodeLoader[];
nodes: Array<string | undefined>;
routes: SSRRoute[];
};
}
10 changes: 5 additions & 5 deletions packages/kit/types/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,13 @@ export interface SSREndpoint {
type: 'endpoint';
pattern: RegExp;
params: GetParams;
load(): Promise<{
[method: string]: RequestHandler;
}>;
file: string;
}

export type SSRRoute = SSREndpoint | SSRPage;

export type CSRRoute = [RegExp, CSRComponentLoader[], CSRComponentLoader[], GetParams?];

export type SSRNodeLoader = () => Promise<SSRNode>;

export interface Hooks {
externalFetch: ExternalFetch;
getSession: GetSession;
Expand Down Expand Up @@ -131,6 +127,10 @@ export interface SSRRenderOptions {
handle_error(error: Error & { frame?: string }, request: ServerRequest<any>): void;
hooks: Hooks;
hydrate: boolean;
load_component: (id: string) => Promise<SSRNode>;
load_endpoint: (file: string) => Promise<{
[method: string]: RequestHandler;
}>;
manifest: SSRManifest;
paths: {
base: string;
Expand Down

0 comments on commit 7b99623

Please sign in to comment.