3.0.0 • Published 3 years ago

@elo7/fastify-svelte v3.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

fastify-svelte

Fastify plugin for using Svelte as a view engine (server-side rendering)

Table of Contents

  1. Installation
  2. Usage
  3. View method's API
  4. Constructor's API
  5. Plugins

Installation

To install this plugin, run the command:

# npm
npm install --save @elo7/fastify-svelte
# yarn
yarn add @elo7/fastify-svelte

Usage

Using your fastify instance, register the plugin:

// src/server.js
import fastify from 'fastify';
import sveltePlugin from 'fastify-svelte';

const app = fastify();
app.register(sveltePlugin);

The plugin accepts some options, which are detailed in the "Constructor's API" section below.

Consider that you have, the following file structure:

|-> rollup.config.js
|-> src/
| |-> server.js
| |-> views/
| |   |-> Home/
| |   |   |-> template.svelte
| |   |-> template/
| |   |   |-> template.js
| |-> controller/
| |   |-> Home.js

In your controller, for returning an visual page as a response do:

// src/controllers/Home.js

app.get('/', (req, reply) => {
	reply.view('Home', { name: 'John Doe' }, { themeColor: '#fff' });
});

This will send the server side rendered home page, constructed using the second argument as props for the page, and the third argument is passed to the generic template as is.

The plugin expects that you have compiled your Svelte templates beforehand to a ES Module format. You can do this by using a bundler such as Rollup or Webpack in your project. For an example, your rollup.config.js could look like this:

import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import glob from 'glob';

const templates = glob.sync('src/**/template.svelte');

const dev = NODE_ENV === 'development';

const serverSideConfig = (template) => ({
	input: template,
	output: {
		file: template.replace('svelte', 'js'),
		format: 'esm',
	},
	plugins: [
		svelte({
			css: (css) => {
				css.write(template.replace('src', 'static/css').replace('svelte', 'css'), false);
			},
			dev,
			generate: 'ssr',
		}),
		resolve(),
		commonjs(),
	],
});

const clientSideConfig = (template) => ({
	input: template,
	output: {
		file: template.replace('src', 'static/js').replace('svelte', 'js'),
		format: 'iife',
		name: 'Page',
	},
	plugins: [
		svelte({
			css: false,
			dev,
			hydratable: true,
		}),
		resolve(),
		commonjs(),
	],
});

export default [
	...templates.map(serverSideConfig),
	...templates.map(clientSideConfig),
];

Your generic template.js should look like this, this will be used as the skeleton for your page, adding meta tags and providing anchors for your svelte page to be mounted, this template receives an object that contains both the css, the script and the html (named as content here) generated by the svelte page compilation, the props used to hydrate the component, once the page is loaded by the user and the extraData passed throgh the controller

// src/views/template/template.js
export default ({ css, script, content, props, extraData }) => `<!DOCTYPE html>
<html lang='en'>

<head>
	<meta charset='utf-8'>
	<meta name='viewport' content='width=device-width, initial-scale=1'>
	<link rel='stylesheet' href='${css}'>
	<meta name="theme-color" content="${extraData.themeColor}">
</head>

<body>
	<div id='content'>
		${content}
	</div>
	<script src='${script}'></script>
	<script>
		new Page({
			hydrate: true,
			props: ${props},
			target: document.getElementById('content'),
		});
	</script>
</body>

</html>`;

View method's API

This plugin will make available the reply.view method, which receives three arguments:

Path (first argument)

Required: true

This is the path of the directory where the file template.svelte is, the plugin's option svelteTemplatesPath will be appended to argument path, as well as the return of the platform option. For an example look at the assetUrlForConstructor explanation.

Props (second argument)

Required: false

This is the props object that will be used to render the component passed through the first argument.

Extra data (third argument)

Required: false

This object will be passed to your generic template.js as is.

Constructor's API

This plugin can receive three options, all are optional:

Platform

Default: () => ''

The platform argument is used to be appended with the path of an specified page. In the example below, the plugin will look for the templates under src/views/<path>/mobile or src/views/<path>/desktop:

const isMobile = (reply) => // implement your logic here.

app.register(sveltePlugin, {
	platform: (reply) => isMobile(reply) ? 'mobile' : 'desktop',
});

SvelteTemplatesPath

Default: <rootdir>/src/views

The svelteTemplatesPath argument is used to specify the path where templates are found. In the example below, the plugin will look for the templates under <rootdir>/src/pageViews:

app.register(sveltePlugin, {
	svelteTemplatesPath: `{__dirname}/pageViews`,
});

Note that the code present in the example assumes that you are calling the plugin's constructor under <rootdir>/src.

AssetUrlForConstructor

Default:

() => (page, type) => {
	return `/static/${type}/views/${page}/template.${type}`;
};

The assetUrlForConstructor argument is used to specify how the path of a page is translated in its assets, the javascript file and the css one. It receives the fastify instance as its only argument, and it must return a function, which receives two arguments and returns a path to an asset. The page argument will be the path given to the reply.view first argument with the return of the platform function appended, for example, if you have a code that look like this:

// src/server.js
app.register(sveltePlugin, {
	platform: () => 'mobile',
});

// src/controllers/Home.js
app.get('/', (req, reply) => {
	return reply.view('pages/Home');
};

The page argument value will be pages/Home/mobile. And the type argument value will be either js or css. Below, we have an example where the asset's path is just static folder and the function logs to the console when a template is found.

app.register(sveltePlugin, {
	assetUrlForConstructor: (app) => {
		app.log.info('Template found');
		return (page, type) => `/static/${page}.${type}`
	}
});

Plugins

This fastify's plugin accepts its own plugins, so you can extend its functionality. The plugins are passed as itens in an array.

import sveltePartialHydration from
'@elo7/fastify-svelte-parital-hydration-plugin`;

app.register(sveltePlugin, {
	plugins: [sveltePartialHydration],
});

Plugins

This fastify's plugin accepts its own plugins, so you can extend its functionality. Each plugins specifies in which stage of the fastify-svelte process and the key that the value returned by the plugin will occupy in the object passed to the template.js. For an example on how to build a plugin, check Partial Hydration Plugin.

3.0.0

3 years ago

2.0.0

3 years ago

1.1.0

3 years ago

1.0.0

3 years ago