svelte-view-engine
svelte-view-engine ==================
Last updated 13 days ago by lightsquare .
Repository · Bugs · Original npm · Tarball · package.json
$ cnpm install svelte-view-engine 
SYNC missed versions from official npm registry.

svelte-view-engine

svelte-view-engine is an Express-compatible view engine that renders Svelte components.

Example app: https://github.com/svelte-view-engine/example.

const svelteViewEngine = require("svelte-view-engine");

let engine = svelteViewEngine({
	template: "./template.html", // see Root template below
	dir: "./pages",
	type: "html",
	init: true,
	watch: true,
	liveReload: true,
	// See Build script below
	buildScript: "./scripts/svelte/build.js",
	buildDir: "/tmp/svelte-build",
	stores: [
		// see Stores/SSR gotchas
	],
});

app.engine(engine.type, engine.render);
app.set("view engine", engine.type);
app.set("views", engine.dir);

// ...

app.get("/", (req, res) => {
	res.render("Home", {
		name: "world" // renders ./pages/Home.html with props {name: "world"}
	});
});

It can also be used outside of Express. svelteViewEngine(options) returns an object with render(path, locals[, callback]). If callback is supplied it is called with (error, html), otherwise a promise is returned.

Design

The motivation behind svelte-view-engine is to be able to build the view layer of a web app using a hierarchy of Svelte components and as little else as possible, while not having to buy in to a full app framework.

It is therefore a view engine (like Pug or EJS) as opposed to an app framework (like Sapper or Next.js).

svelte-view-engine doesn't know how to compile Svelte components itself; you pass it the path to a build script. This allows you to use your existing Svelte build process, or write one for your specific use case. See the example app for an example of this.

Root template

Svelte components and <slot>s take the place of, for example, Pug layouts and mixins for all your re-use and composition needs, but pages still need a bit of surrounding boilerplate HTML that you can't define in Svelte -- <!doctype>, <html> etc -- and you also need a few lines of JS to instantiate the component on the client.

This code is defined in a single root template that's used for all pages, with ${} placeholders for the page content:

// template.html

<!doctype html>
<html>
	<head>
		${head}
		<style>
			${include ./global.css}
			
			${css}
		</style>
	</head>
	<body>
		${html}
		<script>
			props = ${props};
			
			${js}
			
			new ${name}({
				target: document.body,
				props: props,
				hydrate: true,
			});
		</script>
	</body>
</html>
  • head is the SSR-rendered markup from any <svelte:head> tags.
  • css is the CSS.
  • html is the SSR-rendered component markup.
  • js is the clientside component returned by the build script.
  • name is the basename of the .html file, and is used as the clientside component class name.
  • props is a JSON payload of the object you pass to res.render(). See the payloadFormat option for formatting options.
  • include /path/to/file is replaced with the contents of the file.

Build script

This is a separate script, as opposed to a passed-in function, so that the build process doesn't inflate the memory usage of the main app. It should accept one command-line argument, a JSON payload of the following form:

{
	name, // Component
	path, // /src/path/to/Component.html
	buildPath, // /build/path/to/Component.html.json
	noCache, // Don't use cached bundles
	options, // The options passed to svelteViewEngine
}

It should compile the component and write JSON out to buildPath with the following form:

{
	client: {
		cache, // options.cache && bundle.cache
		js, // clientside js
		watchFiles, // list of paths to watch for changes
	},
	server: {
		cache, // options.cache && bundle.cache
		component, // serverside js
		css, // css
	}
}

Props/payload

The svelte-view-engine/payload module makes view locals available to all components, clientside and serverside. To achieve this, the props of the currently-rendering page are stored in a global variable called props. On the server, this holds the original object passed to res.render(). On the client, it's inserted into the root template as a string of JSON. It can be injected into the template in various ways, depending on your setup:

  • set the payloadFormat option to "templateString" to get the props as a template string: props = ${props}; -> props = [backtick]{"a":1}[backtick];

  • evaluate the JSON directly as JavaScript: props = ${props}; -> props = {"a":1};

  • put the JSON string into a script tag:

    <script type="application/json" id="payload">
    	${props}
    </script>
    <script>
    	props = document.getElementById("payload").text;
    	
    	// ...
    </script>
    

Keeping the payload as a string is most flexible, and allows you to parse it with your own code if you don't use export let (if you use export let, it must be a live object that you can pass to the clientside component props option).

You access the props in pages like so:

<script>
	import payload from "svelte-view-engine/payload";
	
	let {
		a, // 1
	} = payload.get();
</script>

You can also just use export let as normal:

<!-- Root template -->

<script>
	${js}
	
	new ${name}({
		target: document.body,
		props: ${props},
		hydrate: true,
	});
</script>

<!-- Page -->

<script>
	export let a; // 1
</script>

When to use payload instead of export let:

  • You want to access the props from a sub-component without having to pass them in explicitly from the top-level page component.

  • You need to process the data somehow before using it, for example to parse it using a JSON reviver function that depends on your app code. In this case you would write a module that reads the payload and exposes the modified version, then use that module in your pages.

Build scheduling

When you modify a component that's used by many pages, with a naive approach all of these pages would immediately see the change and rebuild themselves, meaning you might have to wait for all of them to rebuild before seeing your changes. Also, when building pages for the first time, building them all at once can use up a lot of memory.

To solve these issues there are two features: priority builds/active pages; and the buildConcurrency option.

Active pages

In development, pages keep a websocket open with a regular heartbeat to keep track of whether they're open in a browser (active). On dependency changes, inactive pages wait for 100ms before scheduling themselves for rebuild, to allow active pages to see the change and schedule themselves first. Active pages also pass a "priority" argument to the scheduler, which means they get added to the front of the build queue.

buildConcurrency

buildConcurrency defaults to os.cpus().length, and limits the number of concurrent build processes to limit memory consumption while maximising CPU utilisation.

_rebuild

If props._rebuild is true, the page is rebuilt before being rendered. This can be hooked up to the hard reload feature in Chrome via the Cache-Control header (sometimes it's useful to be able to force a rebuild in development, for example if the app has been offline while making changes to components, in which case they wouldn't be picked up for rebuild and the app would have an out of date version):

app.use(function (req, res, next) {
	if (req.headers["cache-control"] === "no-cache") {
		res.locals._rebuild = true;
	}
	
	next();
});

Stores/SSR gotchas

Svelte stores, and any other global values, must be implemented carefully to avoid sharing values between all users of the app. Since stores are only useful if they're global, and being global on the server means being shared between all users of the app, svelte-view-engine provides a way to register stores so that they can be cleared before each render.

Pass an array of writable stores to the stores option to have them cleared. By default, the value will be set to undefined. To set the value to something else, define a reset method on the store, which will be called instead of set(undefined) if present.

Options

dev = process.env.NODE_ENV !== "production"

template: Path to root template.

payloadFormat: Format of the ${props} placeholder value. Defaults to "json", which inserts a string of JSON directly (must be inserted into a script tag as JSON can contain both single and double quotes). Set to "templateString" to wrap the JSON as a backtick-quoted string. String values in the JSON must not contain unescaped backticks.

dir: Pages directory.

type: File extension (defaults to "html"). It's recommended to use a different extension for pages and components, so that svelte-view-engine doesn't unnecessarily build non-page components it finds in the pages directory (e.g. .html for pages and .svelte for other components).

init: Find all pages (files of type in dir) and build them on startup. Defaults to true. This avoids waiting for the build the first time you request each page.

buildScript: Path to build script.

buildDir: Where to keep built pages. This must be unique per project, e.g. "/tmp/myAppSvelteBuild" or somewhere within the project directory.

buildConcurrency: The maximum number of pages to build concurrently. Defaults to the number of processor cores available.

watch: Watch component files and dependencies and auto-rebuild. Defaults to dev.

liveReload: Auto reload the browser when component rebuilds. Defaults to dev.

liveReloadPort: WebSocket port to use for live reload message. Defaults to a random port between 5000 and 65535 (this will throw an error if the port is in use, so if you're using a process manager it will restart the app until it finds an available port).

minify: Passed through to the build script. Defaults to !dev.

transpile: Passed through to the build script. Defaults to !dev.

excludeLocals: Array of object keys to exclude from the locals that get passed to the component. Some keys are added by Express, and may be unnecessary and/or security concerns if exposed. This defaults to ["_locals", "settings", "cache"] and is overwritten (not merged) with the supplied setting.

saveJs: Save component JS in .client.js and .server.js files in the build dir. Defaults to dev. This is sometimes useful for looking up line numbers from server error logs when the SSR component render function throws an error.

stores: Optional array of writable stores to reset before each call to render. If the store has a reset method, it will be called; otherwise the value will be set to undefined.

Current Tags

  • 9.1.1                                ...           latest (13 days ago)

58 Versions

  • 9.1.1                                ...           13 days ago
  • 9.1.0                                ...           13 days ago
  • 9.0.7                                ...           13 days ago
  • 9.0.6                                ...           15 days ago
  • 9.0.5                                ...           24 days ago
  • 9.0.4                                ...           24 days ago
  • 9.0.3                                ...           24 days ago
  • 9.0.2                                ...           24 days ago
  • 9.0.1                                ...           24 days ago
  • 9.0.0                                ...           24 days ago
  • 8.0.0                                ...           a month ago
  • 7.8.1                                ...           a month ago
  • 7.8.0                                ...           a month ago
  • 7.7.7                                ...           a month ago
  • 7.7.5                                ...           a month ago
  • 7.7.4                                ...           2 months ago
  • 7.7.3                                ...           2 months ago
  • 7.7.2                                ...           2 months ago
  • 7.7.1                                ...           2 months ago
  • 7.7.0                                ...           2 months ago
  • 7.6.0                                ...           2 months ago
  • 7.5.5                                ...           2 months ago
  • 7.5.3                                ...           2 months ago
  • 7.5.2                                ...           2 months ago
  • 7.5.1                                ...           2 months ago
  • 7.5.0                                ...           2 months ago
  • 7.4.1                                ...           2 months ago
  • 7.4.0                                ...           2 months ago
  • 7.3.0                                ...           2 months ago
  • 7.2.0                                ...           2 months ago
  • 7.1.1                                ...           2 months ago
  • 7.0.0                                ...           2 months ago
  • 6.1.1                                ...           2 months ago
  • 6.1.0                                ...           2 months ago
  • 6.0.0                                ...           2 months ago
  • 5.1.0                                ...           2 months ago
  • 5.0.3                                ...           3 months ago
  • 5.0.2                                ...           3 months ago
  • 5.0.1                                ...           4 months ago
  • 5.0.0                                ...           4 months ago
  • 4.0.3                                ...           5 months ago
  • 4.0.2                                ...           5 months ago
  • 4.0.1                                ...           5 months ago
  • 4.0.0                                ...           6 months ago
  • 3.0.0                                ...           6 months ago
  • 2.0.2                                ...           7 months ago
  • 2.0.1                                ...           7 months ago
  • 2.0.0                                ...           7 months ago
  • 1.3.1                                ...           7 months ago
  • 1.3.0                                ...           7 months ago
  • 1.2.0                                ...           7 months ago
  • 1.1.3                                ...           7 months ago
  • 1.1.2                                ...           7 months ago
  • 1.1.1                                ...           7 months ago
  • 1.1.0                                ...           7 months ago
  • 1.0.2                                ...           7 months ago
  • 1.0.1                                ...           8 months ago
  • 1.0.0                                ...           8 months ago
Maintainers (1)
Downloads
Today 0
This Week 58
This Month 137
Last Day 58
Last Week 0
Last Month 198
Dependencies (3)
Dev Dependencies (0)
None
Dependents (0)
None

Copyright 2014 - 2017 © taobao.org |