Those of you who have heard of the Svelte framework have probably heard of it: Unlike React or Vue, Svelte does not use the Virtual DOM. Instead, it compiles the code into native DOM operations and Vanilla JS before deployment, thus running Web applications without relying on the runtime of the framework itself. There is no need to do diff/patch to increase speed and reduce package size. (A simple explanation of svelte can be found in zhihu’s answer.)

With this introduction, a natural question is, how do we do this so-called compilation? Instead of giving a direct answer, the official website recommended that we use REPL, an online editor that renders pages in real time based on input code (similar to CodePen with Svelte). After creating the desired effect on the REPL page, download svelte-app.zip and unzip it to run:

cd /path/to/svelte-app
npm install
npm run dev
Copy the code

You can access the results of the REPL at localhost:5000.

Effects of Svelte REPL

REPL hides the underlying mechanics of Svelte, allowing users to focus only on writing.svelte files, which is really convenient. But to see why and why, today let’s take a look at what the Svelte template project downloaded from the REPL looks like.

Svelte template folder structure

Directly downloading the original REPL application, Hello World in the image above, results in a folder with this structure:

Svelte - app ├ ─ ─. Gitignore ├ ─ ─ the README. Md ├ ─ ─ package. The json ├ ─ ─ a rollup. Config. Js ├ ─ ─ public │ ├ ─ ─ the favicon. PNG │ ├ ─ ─ Global. CSS │ └ ─ ─ index. The HTML ├ ─ ─ scripts | └ ─ ─ setupTypeScript. Js └ ─ ─ the SRC ├ ─ ─ App. Svelte └ ─ ─ main. JsCopy the code

Since the focus of this article is not on the TypeScript usage of Svelte, we can ignore the scripts folder, delete a few files that have nothing to do with the code, and simplify the template to:

Svelte - app ├ ─ ─ package. Json ├ ─ ─ a rollup. Config. Js ├ ─ ─ public │ ├ ─ ─ the favicon. PNG │ ├ ─ ─ global. The CSS │ └ ─ ─ index. The HTML └ ─ ─ the SRC ├ ─ ─ App. Svelte └ ─ ─ the main, jsCopy the code

This structure should look familiar to those familiar with React. Like the template generated by create-react-app, there are two subdirectories SRC and public.

src

The SRC folder contains the Svelte code. The content in app. svelte is the same as that in the screenshot above:

<script>
	let name = 'world';
</script>

<h1>Hello {name}!</h1>
Copy the code

Main.js is the bridge that connects the App to the final page:

import App from './App.svelte';

var app = new App({
	target: document.body
});

export default app;
Copy the code

Here target: document.body is the child node that renders App as body.

public

The public folder contains the final HTML page. PNG is a svelte icon and global. CSS is the default global CSS. Let’s focus on index.html:

<! DOCTYPEhtml>
<html lang="en">
<head>
	<meta charset='utf-8'>
	<meta name='viewport' content='width=device-width,initial-scale=1'>
	<title>Svelte app</title>
	<link rel='icon' type='image/png' href='/favicon.png'>
	<link rel='stylesheet' href='/global.css'>

	<link rel='stylesheet' href='/build/bundle.css'>
	<script defer src='/build/bundle.js'></script>
</head>

<body>
</body>
</html>
Copy the code

There are two points of concern. First, the body in index.html is empty, and SRC /main.js, as mentioned above, fills the content with frames. This is followed by the following lines:

	<link rel='stylesheet' href='/build/bundle.css'>
	<script defer src='/build/bundle.js'></script>
Copy the code

They reference bundle.css and bundle.js, which do not yet exist. These files are the result of compiling, and you can guess that the Svelte template will compile the SRC code into the public/build folder.

How does RollUp build Svelte applications

Knowing the start point (SRC) and end point (public/build), how does the compiler do this conversion? Let’s look at the corresponding package.json, according to the NPM run dev directive that started the project:

{
  "name": "svelte-app"."version": "1.0.0"."scripts": {
    "build": "rollup -c"."dev": "rollup -c -w"."start": "sirv public"},... }Copy the code

NPM run dev is equivalent to rollup -c -w, which means that Svelte is compiled and packaged using rollup. For those of you who don’t know, RollUp is a JavaScript wrapper, similar to Webpack, except RollUp focuses on packaging JavaScript. Rollup -c -w will cause rollup to perform packaging operations, where -c means to use rollup.config.js in the project as the configuration file and -w means to listen for the files to be packed and automatically repack them if changes are made.

So the secret to doing Svelte compilation, and finally hosting static web pages locally, is in rollup.config.js. Let’s first list the entire file here (with a translation of the default English comments) :

import svelte from 'rollup-plugin-svelte';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import css from 'rollup-plugin-css-only';

constproduction = ! process.env.ROLLUP_WATCH;function serve() {
  let server;

  function toExit() {
    if (server) server.kill(0);
  }

  return {
    writeBundle() {
      if (server) return;
      server = require('child_process').spawn('npm'['run'.'start'.The '-'.'--dev'] and {stdio: ['ignore'.'inherit'.'inherit'].shell: true
      });

      process.on('SIGTERM', toExit);
      process.on('exit', toExit); }}; }export default {
  input: 'src/main.js'.output: {
    sourcemap: true.format: 'iife'.name: 'app'.file: 'public/build/bundle.js'
  },
  plugins: [
    svelte({
      compilerOptions: {
        // Enable runtime checking in a non-production environment
        dev: !production
      }
    }),
    // Extract CSS from all components into a single file -- improve performance
    css({ output: 'bundle.css' }),

    // If you have external dependencies installed from NPM, you generally need these plug-ins.
    // There are cases where you need to do additional configuration -- see documentation for details:
    // https://github.com/rollup/plugins/tree/master/packages/commonjs
    resolve({
      browser: true.dedupe: ['svelte']
    }),
    commonjs(),

    // In a non-production environment, run 'NPM run start' after the package is generated! production && serve(),// In non-production environments, refresh the browser when changes are made in the 'public' directory! production && livereload('public'),

    // If you build for production (NPM run build instead of NPM run dev),
    // minify
    production && terser()
  ],
  watch: {
    clearScreen: false}};Copy the code

Rollup.config.js generic structure

Let’s first pick out the general structure of the RollUp configuration, which is:

export default {
  input: 'src/main.js'.// Input file SRC /main.js
  output: {
    sourcemap: true.Function () {code})()
    / / see: https://en.wikipedia.org/wiki/Immediately_invoked_function_expression
    format: 'iife'.name: 'app'.// Output to public/build/bundle.js
    file: 'public/build/bundle.js'
  },
  plugins: [...]. .watch: {
    // Do not empty the terminal while repacking
    clearScreen: false}};Copy the code

This code confirms what we guessed above, which is that RollUp packages SRC files to public/build/bundle.js. What about the.svelte file? This depends on the RollUp plug-in used by the Svelte template.

A RollUp plug-in

export default{...plugins: [
    svelte({
      compilerOptions: {
        // Enable runtime checking in a non-production environment
        dev: !production
      }
    }),
    // Extract CSS from all components into a single file -- improve performance
    css({ output: 'bundle.css' }),

    // If you have external dependencies installed from NPM, you generally need these plug-ins.
    // There are cases where you need to do additional configuration -- see documentation for details:
    // https://github.com/rollup/plugins/tree/master/packages/commonjs
    resolve({
      browser: true.dedupe: ['svelte']
    }),
    commonjs(),

    // In a non-production environment, run 'NPM run start' after the package is generated! production && serve(),// In non-production environments, refresh the browser when changes are made in the 'public' directory! production && livereload('public'),

    // If you build for production (NPM run build instead of NPM run dev),
    // minify
    production && terser()
  ],
  ...
};
Copy the code

Plug-ins are executed in the order defined. Here we can divide plug-ins into three groups.

1. Svelte compiler plug-in

import svelte from 'rollup-plugin-svelte';
import css from 'rollup-plugin-css-only';

export default{...plugins: [
    svelte({
      compilerOptions: {
        // Enable runtime checking in a non-production environment
        dev: !production
      }
    }),
    // Extract CSS from all components into a single file -- improve performance
    css({ output: 'bundle.css'}),... ] . };Copy the code

Rollup-plugin-svelte will call the svelte compiler to compile. Due to space limitations, I will disassemble this plugin in detail in a future article. All you need to know for now is:

  • In the default configuration,rollup-plugin-svelteWill compile all of them.svelteFile;
  • rollup-plugin-svelteUsed successivelysvelteIn the packagepreprocesscompilerFunction.

Rollup-plugin-css-only is a plug-in that is not directly related to Svelte, but is required to combine CSS because the Svelte compiler handles CSS fragments for each component separately.

2. General purpose plug-ins

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

export default{...plugins: [...// If you have external dependencies installed from NPM, you generally need these plug-ins.
    // There are cases where you need to do additional configuration -- see documentation for details:
    // https://github.com/rollup/plugins/tree/master/packages/commonjs
    resolve({
      browser: true.dedupe: ['svelte'] }), commonjs(), ... ] . };Copy the code

The second group is the two generic plug-ins for RollUp, resolve for plugging dependencies into a package, and CommonJS for converting commonJS modules to ES2015 for RollUp to handle. See the RollUp documentation for a use case description of both plug-ins.

3. Plug-ins for debugging environment and production environment

import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';

constproduction = ! process.env.ROLLUP_WATCH;export default{...plugins: [...// In a non-production environment, run 'NPM run start' after the package is generated! production && serve(),// In non-production environments, refresh the browser when changes are made in the 'public' directory! production && livereload('public'),

    // If you build for production (NPM run build instead of NPM run dev),
    // minify
    production && terser()
  ],
  ...
};
Copy the code

In the configuration file of the template project, determine whether you are in production by checking whether RollUp listening (ROLLUP_WATCH) is enabled. The last group of three plug-ins is dependent on whether they are in production or not. The role of livereload and Terser has been made clear in the notes, so I won’t go into it again. Let’s take a look at the serve plugin. It is the only plug-in written in a configuration file, and it plays a key role in hosting static web pages. Its source code is as follows:

function serve() {
  let server;

  function toExit() {
    if (server) server.kill(0);
  }

  return {
    writeBundle() {
      if (server) return;
      server = require('child_process').spawn('npm'['run'.'start'.The '-'.'--dev'] and {stdio: ['ignore'.'inherit'.'inherit'].shell: true
      });

      process.on('SIGTERM', toExit);
      process.on('exit', toExit); }}; }Copy the code

Serve uses RollUp’s hook function writeBundle, which is called when the package is complete. For Serve, this is to spawn a new process when the package is finished, running NPM Run Start. Package. json will run:

sirv public
Copy the code

Sirv is a CLI application for hosting static files, and the Svelte template uses it for the final preview.

Svelte REPL is a template that can be used to create a template for the Svelte REPL. In a future post, I’ll take it a step further and talk about what’s going on in rollup-plugin-svelte, so be sure to give it a thumbs up if you enjoyed it!