https://github.com/johannschopplich/plain-spa
🦢 Modern SPA deployable as-is without any bundlers
https://github.com/johannschopplich/plain-spa
dom javascript reactive sinuous spa
Last synced: about 1 year ago
JSON representation
🦢 Modern SPA deployable as-is without any bundlers
- Host: GitHub
- URL: https://github.com/johannschopplich/plain-spa
- Owner: johannschopplich
- License: mit
- Archived: true
- Created: 2020-03-27T10:04:00.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2020-06-30T12:49:36.000Z (almost 6 years ago)
- Last Synced: 2025-05-07T12:48:40.898Z (about 1 year ago)
- Topics: dom, javascript, reactive, sinuous, spa
- Language: JavaScript
- Homepage: https://plain-spa.jhnn.dev
- Size: 974 KB
- Stars: 14
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Plain SPA
Modern single-page application deployable as-is without any bundlers
## Key Features
This boilerplate uses:
- [Sinuous](https://github.com/luwes/sinuous) (1247 bytes fast, reactive UI library),
- [Storeon](https://github.com/storeon/storeon) (167 bytes event-based Redux-like state manager) and
- [Storeon Router](https://github.com/storeon/router) (570 bytes modern router) under the hood.
All three tiny libraries come at cost of just 2 kilobytes combined. I chose them carefully to not reinvent the wheel after looking up a lot of lightweight UI and router libraries.
For example Sinuous comes up with **tagged templates** and **observables**:
```js
import { observable, html } from './modules/sinuous/index.js'
const counter = observable(0)
const view = () => html`
Counter ${counter}
`
document.body.append(view())
setInterval(() => counter(counter() + 1), 1000)
```
The app includes several example routes to show Storeon Router's capabilities.
## Background
Although I fell in love with the possibilities offered by today's libraries like Vue or React, the tooling around them throws me off sometimes. Grasping how the dependencies interact with each other. Hundreds of megabytes for transpiling all the code. Recently I had to dig deep into Webpack's internals to figure out how to omit the asset size evaluation of images inside the public folder.
If one deviates from the standard tooling, working with it quickly becomes uncomfortable.
Sine ES6+ features are available in modern browsers by default, there will be no advantage of transpiling in the future (hopefully). In service workers they are used regularly in this very moment.
I wanted to create a simple SPA with some of the glory provided by bigger frameworks, but keep the setup as simple as possible to understand what is actually happening. Plain JavaScript, runnable in the browsers without bundling or a `dist` directory to deploy.
To drop `npm` itself as a dependency, the packages in use have been imported manually into `js/modules/*`. That sure isn't best practice, but let's you clone the repository and execute it in an instant.
## Bundling
> Doesn't the headline say "deployable as-is without any bundlers"?
Absolutely. The project is ready to ship for production purposes.
**However**, you can tree-shake and compile htm syntax to hyperscript for a smaller app footprint.
```js
// E.g. the following input:
html`
hello ${you}
`
// becomes:
h('div', { id: 'foo' }, 'hello ', you)
```
Run `npm i && npm run build` to bundle and minify your app. I tried to decrease the tooling as much as possible. Merely 10 Megabytes (unpacked) of Node modules will be installed.
Finally change the source path to the entry script file inside `index.html` to `/build/bundle.js`.
This example application bundled amounts to **3294 bytes** in total.
## Syntax Highlighting
Syntax highlighting for HTML in ES6 multiline strings is probably not covered by your code editor of choice by default. If you're using Visual Studio Code, I recommend [es6-string-html](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html) to add support.