Introduction to Svelte -- implementing cross framework component reuse with Web Components

Keywords: Front-end spreadjs svelte

Svelte is a new method of building Web applications. It has been tepid since its launch. It has not become the fourth largest framework after Angular, React and VUE, but it has not lost its popularity and nobody cares. An important reason for this is that svelte's core idea is to reduce the amount of code in the framework runtime through static compilation. It can be developed like React and VUE, but there is no virtual DOM., So svelte can compile the code into JS code that is small and independent of the framework.

It seems full of advantages, but it is too flexible to write highly consistent business code. The above advantages are not well reflected in actual large projects.

Svelte's framework is not perfect, but it didn't die in the cruel market competition because it has a special secret script and some functions that make it an irreplaceable member of other frameworks..

For Svelte, the name of this script is Web Components.

In a large project completed by multiple teams, each team may use different framework versions or even different frameworks, which makes it difficult to reuse components between different projects. "write one, run anywhere" is empty talk. In this case, Svelte becomes a bridge to bridge the framework gap. The framework independent Web Components developed by Svelte can be reused among various frameworks. At the same time, Svelte's development method is not as cumbersome as writing pure js.

Taking SpreadJS integration as an example, the following describes how to develop a spread sheets web component with Svelte for reuse by other pages.

  1. Create the Svelte template project.
    svelte officially provides the template project, just clone or download the project.

https://github.com/sveltejs/component-template

npx degit sveltejs/component-template my-new-component
cd my-new-component
npm install # or yarn
  1. Modify rollup.config.js, add customElement: true configuration, and the output is a web component component.

The added rollup.config.js is as follows.

import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';
import pkg from './package.json';

const name = pkg.name
        .replace(/^(@\S+\/)?(svelte-)?(\S+)/, '$3')
        .replace(/^\w/, m => m.toUpperCase())
        .replace(/-\w/g, m => m[1].toUpperCase());

export default {
        input: 'src/index.js',
        output: [
                { file: pkg.module, 'format': 'es' },
                { file: pkg.main, 'format': 'umd', name }
        ],
        plugins: [
                svelte({
                        customElement: true,
                }),
                resolve()
        ],
};
  1. Update src/Component.svelte to create the spread sheets component.
<svelte:options tag="spread-sheets" />
<script>
    import { createEventDispatcher, onMount } from 'svelte';
    // Event handling
    const dispatch = createEventDispatcher();
    export let value ="";
    $: valueChanged(value);
    function valueChanged(newValue) {
      console.log("value changed", newValue);
      if(spread){
        let sheet = spread.getActiveSheet();
        sheet.setValue(0, 0, value);
      }
    }

    let spreadHost;
    let spread;
    function dispatchEvent(name, e) {
      // dispatch(name, e);
      const event = new CustomEvent(name, {
        detail: e,
        bubbles: true,
        cancelable: true,
        composed: true, // this line allows the event to leave the Shadow DOM
      });
      // console.log(event)
      spreadHost.dispatchEvent(event);
    }
      onMount(() => {
          spread = new GC.Spread.Sheets.Workbook(spreadHost);
          let sheet = spread.getActiveSheet();
          sheet.setValue(0, 0, value);
          spread.bind(GC.Spread.Sheets.Events.ValueChanged, function(s, e){
            e.evnetName = "ValueChanged";
            dispatchEvent("changed", e);
          });
          spread.bind(GC.Spread.Sheets.Events.RangeChanged, function(s, e){
            e.evnetName = "RangeChanged";
            dispatchEvent("changed", e);
          });
      });



  </script>
  <style>
      
  </style>
  <div bind:this={ spreadHost} style="width: 100%; height:100%"></div>

In this way, our custom components are created. Just call npm run build to compile the spread sheets component.

  1. Reference the component on the page.
    Create the index.html page and reference the compiled js file. At the same time, the related resources of spreadjs are introduced.
    Add SpreadJS directly using the spread sheets tag.
<!doctype html>
<html lang="en">
  <head>
    <meta name="spreadjs culture" content="zh-cn" />
    <meta charset="utf-8" />
    <title>My Counter</title>
    <base href="/">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" type="text/css" href="https://demo.grapecity.com.cn/spreadjs/SpreadJSTutorial/zh/purejs/node_modules/@grapecity/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
  </head>
  <body>
    <!-- <spread-sheets-designer></spread-sheets-designer> -->
    <button onclick="getJSON()">GetJSON</button>
    <spread-sheets value="123" style="display:block; width: 80%; height: 400px;"></spread-sheets>


    <script src="https://demo.grapecity.com.cn/SpreadJS/WebDesigner/lib/spreadjs/scripts/gc.spread.sheets.all.14.1.3.min.js" type="text/javascript"></script>

    <script type="text/javascript" src="/dist/index.js"></script>
    <script type="text/javascript">

      document.querySelector("spread-sheets").addEventListener("changed", function(){
        console.log(arguments)
      })

      window.onload = function(){
        document.querySelector("spread-sheets").setAttribute("value", "234");
      }

    </script>
  </body>
</html>

The effect after adding is shown in the figure below.

summary

Although it seems that the Web Component perfectly solves the reuse problem between components, the Web Component developed with Svelte also has some limitations: for example, it can only pass string attribute; The bound attribute is a one-way binding. If you want to obtain the internal update value of the component, you need to bind event to obtain it.

If you are more interested in Svelte, please leave a message~

Posted by sureshp on Tue, 23 Nov 2021 20:49:34 -0800