GithubHelp home page GithubHelp logo

hrbrmstr / rollup-vanilla-webr Goto Github PK

View Code? Open in Web Editor NEW
4.0 3.0 0.0 1021 KB

πŸ§ͺ Vanilla JS WebR + Rollup For Smaller & Easier Deploys

Home Page: https://rud.is/w/rollup-vanilla-webr/

CSS 14.01% HTML 9.67% Just 6.07% JavaScript 70.25%
r rollup rollupjs rstats webr webr-experiment

rollup-vanilla-webr's Introduction

πŸ§ͺ Vanilla JS WebR + Rollup For Smaller & Easier Deploys

See it live before reading!

Yo Yo Yo!

Vanilla JS is the best! Except when it's not.

Even this tiny app of ours is a tad bloated and makes a scandalous number of network connections on first load. Part of that due to us loading entire JS modules when we only need pieces of them. Truth be told, another part is due to me not realizing that including md in the list of languages I wanted Shiki (the syntax highlighter) to support included like every language definition b/c ofc it did.

Anyway…

In this experiment, we're going to rollup our sleeves and tighten things up a bit. We're still staying in unadulterated Vanilla JS land, but we're going to lean on some tooling from the Node.js ecosystem to help our project go on a diet when we deploy it to a real environment.

Before we do that, I feel compelled to go over a couple changes I've made to the previous application to help support this weight reduction program. Here's the updated directory structure with noted about what'd been added or changed; I'll only be covering said changes, so see the previous entries for what everything is for:

rollup-vanilla-webr
β”œβ”€β”€ README.md
β”œβ”€β”€ css
β”‚   └── style.css
β”œβ”€β”€ dist # <--------------------------- This is new!
β”‚   β”œβ”€β”€ index.browser.mjs
β”‚   └── onig.wasm
β”œβ”€β”€ favicon.ico
β”œβ”€β”€ img
β”‚   └── preview.png
β”œβ”€β”€ index.html # <--------------------- This has been modified.
β”œβ”€β”€ justfile # <----------------------- This has been modified.
β”œβ”€β”€ languages # <---------------------- This is new!
β”‚   β”œβ”€β”€ css.tmLanguage.json
β”‚   β”œβ”€β”€ html.tmLanguage.json
β”‚   β”œβ”€β”€ java.tmLanguage.json
β”‚   β”œβ”€β”€ javascript.tmLanguage.json
β”‚   β”œβ”€β”€ json.tmLanguage.json
β”‚   β”œβ”€β”€ markdown.tmLanguage.json
β”‚   β”œβ”€β”€ nginx.tmLanguage.json
β”‚   β”œβ”€β”€ python.tmLanguage.json
β”‚   β”œβ”€β”€ r.tmLanguage.json
β”‚   β”œβ”€β”€ shellscript.tmLanguage.json
β”‚   β”œβ”€β”€ typescript.tmLanguage.json
β”‚   └── xml.tmLanguage.json
β”œβ”€β”€ main.js # <------------------------ This has been modified.
β”œβ”€β”€ md
β”‚   └── main.md
β”œβ”€β”€ package.json # <------------------- This is new!
β”œβ”€β”€ r.js
β”œβ”€β”€ renderers.js # <------------------- This has been modified.
β”œβ”€β”€ rollup.config.js # <--------------- This is new!
β”œβ”€β”€ themes
β”‚   └── ayu-dark.json
β”œβ”€β”€ utils.js
β”œβ”€β”€ wc
β”‚   β”œβ”€β”€ region-plot.js
β”‚   β”œβ”€β”€ select-list.js
β”‚   └── status-message.js
β”œβ”€β”€ webr-serviceworker.js.map
└── webr-worker.js.map

I finally figured out how to get Shiki loaded as a local ES6 module, which is why there's a dist/ folder. I did this for many reasons, but one big one was to get it out of index.html so we could ship it from wherever we deploy it vs hit the CDN. Shiki is hard coded to use dist/ and I didn't feel like re-bundling it to be more flexible (I will read up to see if it's configurable when called). The languages/ and themes/ folders go with it, and since I figured out why it was loading way too many language support files, I pared those down quite a bit to just what we're using.

We got rid of the Web Components in index.html and now load them as modules in main.js via:

import "./wc/region-plot.js"
import "./wc/select-list.js"
import "./wc/status-message.js"

This enables them to be "rolled up" when we're ready to do so.

In renderers.js we now import Shiki:

import * as shiki from './dist/index.browser.mjs';

Overall, this was just minor surgery, and we'll cover package.json in the next section.

Giving In To Node/npm/npx

To use Rollup we need a JS runtime environment and Node is as good as any since we're just using it to run rollup. So, please install npm before continuing.

Now, we'll install npx, which is just an easier way to run npm JS scripts, then rollup, globally to have it around for the future, and then install it local to the project along with some rollup helpers we'll be using.

npm install -g npx
npm install rollup --global 
npm install

You now have a node_modules directory in the project directory. It's HUGE (yes, I am going to make you scroll past ~140 entries):

node_modules
β”œβ”€β”€ @ampproject
β”œβ”€β”€ @babel
β”œβ”€β”€ @gar
β”œβ”€β”€ @jridgewell
β”œβ”€β”€ @nodelib
β”œβ”€β”€ @npmcli
β”œβ”€β”€ @tootallnate
β”œβ”€β”€ @types
β”œβ”€β”€ @web
β”œβ”€β”€ acorn
β”œβ”€β”€ agent-base
β”œβ”€β”€ agentkeepalive
β”œβ”€β”€ aggregate-error
β”œβ”€β”€ ansi-styles
β”œβ”€β”€ array-union
β”œβ”€β”€ balanced-match
β”œβ”€β”€ brace-expansion
β”œβ”€β”€ braces
β”œβ”€β”€ browserslist
β”œβ”€β”€ buffer-from
β”œβ”€β”€ cacache
β”œβ”€β”€ camel-case
β”œβ”€β”€ caniuse-lite
β”œβ”€β”€ chalk
β”œβ”€β”€ chownr
β”œβ”€β”€ clean-css
β”œβ”€β”€ clean-stack
β”œβ”€β”€ color-convert
β”œβ”€β”€ color-name
β”œβ”€β”€ colorette
β”œβ”€β”€ commander
β”œβ”€β”€ concat-map
β”œβ”€β”€ convert-source-map
β”œβ”€β”€ data-uri-to-buffer
β”œβ”€β”€ debug
β”œβ”€β”€ depd
β”œβ”€β”€ dir-glob
β”œβ”€β”€ dot-case
β”œβ”€β”€ electron-to-chromium
β”œβ”€β”€ encoding
β”œβ”€β”€ err-code
β”œβ”€β”€ escalade
β”œβ”€β”€ escape-string-regexp
β”œβ”€β”€ fast-glob
β”œβ”€β”€ fastq
β”œβ”€β”€ fill-range
β”œβ”€β”€ fs-extra
β”œβ”€β”€ fs-minipass
β”œβ”€β”€ fs.realpath
β”œβ”€β”€ fsevents
β”œβ”€β”€ gensync
β”œβ”€β”€ glob
β”œβ”€β”€ glob-parent
β”œβ”€β”€ globals
β”œβ”€β”€ globby
β”œβ”€β”€ graceful-fs
β”œβ”€β”€ has-flag
β”œβ”€β”€ he
β”œβ”€β”€ html-minifier-terser
β”œβ”€β”€ http-cache-semantics
β”œβ”€β”€ http-proxy-agent
β”œβ”€β”€ https-proxy-agent
β”œβ”€β”€ humanize-ms
β”œβ”€β”€ iconv-lite
β”œβ”€β”€ ignore
β”œβ”€β”€ imurmurhash
β”œβ”€β”€ indent-string
β”œβ”€β”€ infer-owner
β”œβ”€β”€ inflight
β”œβ”€β”€ inherits
β”œβ”€β”€ ip
β”œβ”€β”€ is-extglob
β”œβ”€β”€ is-glob
β”œβ”€β”€ is-lambda
β”œβ”€β”€ is-number
β”œβ”€β”€ is-plain-object
β”œβ”€β”€ js-tokens
β”œβ”€β”€ jsesc
β”œβ”€β”€ json5
β”œβ”€β”€ jsonfile
β”œβ”€β”€ lower-case
β”œβ”€β”€ lru-cache
β”œβ”€β”€ make-fetch-happen
β”œβ”€β”€ merge2
β”œβ”€β”€ micromatch
β”œβ”€β”€ mime-db
β”œβ”€β”€ mime-types
β”œβ”€β”€ minimatch
β”œβ”€β”€ minipass
β”œβ”€β”€ minipass-collect
β”œβ”€β”€ minipass-fetch
β”œβ”€β”€ minipass-flush
β”œβ”€β”€ minipass-pipeline
β”œβ”€β”€ minipass-sized
β”œβ”€β”€ minizlib
β”œβ”€β”€ mkdirp
β”œβ”€β”€ ms
β”œβ”€β”€ negotiator
β”œβ”€β”€ no-case
β”œβ”€β”€ node-releases
β”œβ”€β”€ once
β”œβ”€β”€ p-map
β”œβ”€β”€ param-case
β”œβ”€β”€ parse5
β”œβ”€β”€ pascal-case
β”œβ”€β”€ path-is-absolute
β”œβ”€β”€ path-type
β”œβ”€β”€ picocolors
β”œβ”€β”€ picomatch
β”œβ”€β”€ promise-inflight
β”œβ”€β”€ promise-retry
β”œβ”€β”€ queue-microtask
β”œβ”€β”€ relateurl
β”œβ”€β”€ retry
β”œβ”€β”€ reusify
β”œβ”€β”€ rimraf
β”œβ”€β”€ rollup
β”œβ”€β”€ rollup-plugin-copy
β”œβ”€β”€ rollup-plugin-url-resolve
β”œβ”€β”€ run-parallel
β”œβ”€β”€ safer-buffer
β”œβ”€β”€ semver
β”œβ”€β”€ slash
β”œβ”€β”€ smart-buffer
β”œβ”€β”€ socks
β”œβ”€β”€ socks-proxy-agent
β”œβ”€β”€ source-map
β”œβ”€β”€ source-map-support
β”œβ”€β”€ ssri
β”œβ”€β”€ supports-color
β”œβ”€β”€ tar
β”œβ”€β”€ terser
β”œβ”€β”€ to-fast-properties
β”œβ”€β”€ to-regex-range
β”œβ”€β”€ tslib
β”œβ”€β”€ unique-filename
β”œβ”€β”€ unique-slug
β”œβ”€β”€ universalify
β”œβ”€β”€ update-browserslist-db
β”œβ”€β”€ wrappy
└── yallist

May I never complain about the {tidyverse} dependency Hades ever again.

We're now ready to roll things up.

Rollup Time!

The last "new" file is rollup.config.js. Think of this like a "justfile" or "Makefile" with some extra bits tacked on. It's just instructions for how we want to get our project put into a better format for serving in production:

// this is what were using from what we put into `package.json`
import urlResolve from 'rollup-plugin-url-resolve';
import { rollupPluginHTML as html } from '@web/rollup-plugin-html';
import copy from 'rollup-plugin-copy';

export default [
  {
    
    input: './main.js', // rollup will inspect this 
                        // and the entire tree of imports it relies on
    output: {
      dir: 'build',     // We're putting all the output files/dirs here
      format: 'es'      // And we still want ES6 modules
    },
    
    plugins: [
      urlResolve({ // πŸ‘ˆπŸΌ see below the code
        cacheManager: '.cache',
        minify: true,
      }),
      html({ // πŸ‘ˆπŸΌ see below the code
        input: 'index.html',
        minify: true,
      }),
      copy({ // πŸ‘ˆπŸΌ see below the code
        targets: [
          { src: 'dist/onig.wasm', dest: 'build/dist' },
          { src: 'md/**/*', dest: 'build/md' },
          { src: 'languages/**/*', dest: 'build/languages' },
          { src: 'themes/**/*', dest: 'build/themes' },
          { src: 'img/**/*', dest: 'build/img' },
          { src: '*.map', dest: 'build' },
          { src: 'favicon.ico', dest: 'build' },
        ]
      })
    ]
    
  }
];

Plain ol' rollup will just care about the JS dependencies. If we have extra bits we need to put into the build directory, we have to tell it to do that. One way is to use that "copy" plugin and specify stuff by hand. For small projects like these, that's 100% fine.

The html plugin will also figure out things to add from our index.html (like the CSS file). It would have handled the <script> tags, too, but it would have kept us relying on a CDN for Shiki. Blech.

urlResolve lets me me lazy and still rely on CDNs during development. It'll fetch and .cache those resources so they can be further scrunched, shaken and come along for the ride from our server.

The justfile has been changed to give us a "rollup" job:

rollup:
  rm -rf build/
  npx rollup --config # use the default config file

After a just rollup we have a new build/ directory!

build
β”œβ”€β”€ assets
β”‚   └── style-5c0658bc.css
β”œβ”€β”€ dist
β”‚   └── onig.wasm
β”œβ”€β”€ favicon.ico
β”œβ”€β”€ img
β”‚   └── preview.png
β”œβ”€β”€ index.html
β”œβ”€β”€ languages
β”‚   β”œβ”€β”€ css.tmLanguage.json
β”‚   β”œβ”€β”€ html.tmLanguage.json
β”‚   β”œβ”€β”€ java.tmLanguage.json
β”‚   β”œβ”€β”€ javascript.tmLanguage.json
β”‚   β”œβ”€β”€ json.tmLanguage.json
β”‚   β”œβ”€β”€ markdown.tmLanguage.json
β”‚   β”œβ”€β”€ nginx.tmLanguage.json
β”‚   β”œβ”€β”€ python.tmLanguage.json
β”‚   β”œβ”€β”€ r.tmLanguage.json
β”‚   β”œβ”€β”€ shellscript.tmLanguage.json
β”‚   β”œβ”€β”€ typescript.tmLanguage.json
β”‚   └── xml.tmLanguage.json
β”œβ”€β”€ main.js
β”œβ”€β”€ md
β”‚   └── main.md
β”œβ”€β”€ themes
β”‚   └── ayu-dark.json
β”œβ”€β”€ webr-serviceworker.js.map
└── webr-worker.js.map

You should poke at main.js and index.html to see how mangled they are.

The rsync just job is now rsync -avp ./build/ rud.is:~/rud.is/w/rollup-vanilla-webr/: it is literally how i deployed what you're seeing.

Proving It's Better

https://rud.is/w/lit-webr-plot/ makes over 80 HTTP requests, with most hitting the jsdelivr CDN. The Network tab of DevTools scrolls too much to see it.

Here's what our reduced version does (just over 20):

FIN

We are by no means finished with optimizing things, but this "rollup" thing can be a bit intimidating for folks who aren't JS natives.

Hit up GH: https://github.com/hrbrmstr/rollup-vanilla-webr for the source and drop any issues if anything needs more explanation.

Brought to you by @hrbrmstr

rollup-vanilla-webr's People

Contributors

hrbrmstr avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.