openscd / open-scd

A substation configuration description editor for projects using SCL IEC 61850-6 Edition 2 or greater
https://openscd.github.io
Apache License 2.0
101 stars 37 forks source link

OpenSCD as custom element published on npm #1483

Open trusz opened 7 months ago

trusz commented 7 months ago

PR:

trusz commented 7 months ago

We have a few global things going on in our index.html

Settings

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="Description"
    content="Open Substation Communication Designer is a bottom-up system configuration tool for projects described using IEC 61850-6 Edition 2 or greater.">
<base href="/">

External Stylesheets

  <!-- Original URL from Google: https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300&family=Roboto:wght@300;400;500&display=swap -->
  <link href="public/google/fonts/roboto-v27.css" rel="stylesheet">
  <link href="public/google/fonts/roboto-mono-v13.css" rel="stylesheet">
  <!-- Original URL from Google: https://fonts.googleapis.com/css?family=Material+Icons+Outlined&display=block -->
  <link href="public/google/icons/material-icons-outlined.css" rel="stylesheet">
  <link href="public/css/normalize.css" rel="stylesheet">

Favicons

  <link rel="manifest" href="manifest.json">
  <link rel="icon" type="image/png" sizes="16x16" href="public/favicon-16x16.png">
  <link rel="icon" type="image/png" sizes="32x32" href="public/favicon-32x32.png">
  <link rel="icon" type="image/png" sizes="192x192" href="public/icon-192x192.png">

Protection of Duplicate Custom Tags

<script>
const _customElementsDefine = window.customElements.define;
window.customElements.define = (name, cl, conf) => {
  if (!customElements.get(name)) {
    _customElementsDefine.call(window.customElements, name, cl, conf);
   }
};
</script>

Registering Services Workers

<script>
  if ('serviceWorker' in navigator)
    navigator.serviceWorker.register('/sw.js');
</script>

Prevention of Data/Work Loss on Closing OpenSCD

  <script>
    const openScd = document.querySelector("open-scd");
    addEventListener("beforeunload", e => {
      if (openScd && openScd.doc) {
        e.preventDefault();
        return e.returnValue = "Are you sure you want to exit?";
      }
    });
  </script>

All these things still need to work when we use OpenSCD as a single custom element. The nice thing is that, the elements does not necessarily need to be in the <head>. We can put them into a wrapper element that behaves like the index.html. However this element would scope everything into its own shadow DOM. For that we can create a light DOM element by using the createRenderRoot function:

  protected createRenderRoot(): Element | ShadowRoot {
    return this;
  }

This opts out a lot of custom element features but in this wrapper we don't need anything.

Our index.html becomes a really bare bones structure

<!doctype html>
<html lang="en">
  <head>
  </head>

  <body>
    <open-scd-wrapper></open-scd-wrapper>
    <script type="module" src="./src/open-scd-wrapper.js"></script>
  </body>
</html>
trusz commented 7 months ago

I've managed to setup a build that bundles a big chunk of code into a single file with esbuild:

esbuild --bundle --minify --sourcemap --target=es2020\
        --platform=browser --format=esm --outdir=build src/open-scd-wrapper.ts

this works if I run npm run build before and I use the above mentioned index.html npm run build copies over assets, each file compiled to the src folder _snowpack files and node_modules and a few more things. Unfortunately these things are needed.

We could deploy this as a package maybe or try to figure out how to bundle everything into a smaller package

trusz commented 7 months ago

I have tried to do it with Vite, but it does not like dynamic imports, even with plugins it does not compile something that is not referenced so OpenSCD could not load the plugins. There might be some configurations with which I could force vite to compile every file, but I did not find a solution in reasonable time.

Next, I will try to publish the whole build to npm but I think everything it will try to load from the public will fail.

trusz commented 7 months ago
image

Publishing the whole build folder works, but the assets are not loading through unkpg.com, but could load if deployed to github pages

trusz commented 7 months ago

Deploying to GitHub Pages worked for the plugins. Or at least they load.

image

However, the assets are not yet correct. I think I would bundle every asset that we need so you don't have to depend on some setup or fix location for them.

What does not work is the suppression of duplicate custom tags

image

I also got this "undefined entity" error

image

and the plugins don't seem to work either

image
trusz commented 7 months ago

After a talk with the team we agreed on that distributions take care of:

Each plugin will have its own package and there will be an essential plugin package that contains the official essential plugins: