Webformula core
Welcome Getting started Routing Serve / Build Binding variables Web component Fetcher Multiple languages github-circle-black-transparent GitHub github-circle-black-transparent Example app

Getting started

Build a basic web application
Install
            
      npm install @webformula/core
            
          
index.html
            
      <!doctype html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="Cache-Control" content="no-store" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
      <title></title>
      
      <!-- load js and css -->
      <link href="app.css" rel="stylesheet">
      <script src="app.js" type="module"></script>
    </head>
    
    <body>
      <!-- page template render into this element -->
      <page-content></page-content>
    </body>
  </html>
            
          
Routing
@Webformula/core uses directory based routing. All routes go in a 'routes' folder.
            
      app/
  └── routes/
      ├── index/
      │   └── index.js     # /
      ├── 404/
      │   └── index.js     # /404 (or any url that is not found)
      ├── one/
      │   └── index.js     # one/
      ├── two[id?]/
      │   └── index.js     # two/:id?
      ├── three/
      │   └── [id]/
      │       └── index.js # three/:id
      └── four/
          └── [...all]/
              └── index.js # four/* (four/a/b/)
            
          
app/routes/index/index.js → /
app/routes/one/index.js → one
app/routes/two[id?]/index.js → two/:id?
app/routes/three/[id]/index.js → three/:id
app/routes/four/[...rest]/index.js → four/*
Directory route details
routes/index/index.js Root page (/)
routes/404/index.js Not found page. Auto redirect on non matching routes
index.js Route component file
[id] Directory that represents a url parameter
[id?] Directory that represents an options url parameter
name[id?] Inline url parameter to avoid sub folder
[...rest] Directory that represents catch-all route
[...rest?] Directory that represents optional catch-all route
Config app
Change settings for binding and routing
            
      <!-- Add script tag with configuration to index.html -->
  <head>
    ...
    <script>
      /* If false then variable binding will be disabled
      * 
      * Default: true
      */
      window.webformulaCoreBinding = true;


      /* If false then navigation will retrieve pages from the server
      *   Application code and styles will be cached, only the page html will be retrieved
      * 
      * Default: true
      */
      window.webformulaCoreSpa = true;
    </script>
    ...
  </head>
  <body>...</body>
  
            
          
Main application file
app.js
Required: Automatically uses app.js as entry file for bundling
            
      /* Main app file
      * you can import any code in here
      */
      
      import someModule from './someModule.js';
      
      // routes are automatically loaded based on directory routing
            
          
Prevent navigation allows you to lock down the app for uses like authentication
            
      import { routes, preventNavigation } from '@webformula/core';
      import home from './routes/home/index.js';
      import login from './routes/login/index.js';
      
      routes([
        { path: '/', component: home },
        { path: '/login', component: login }
      ]);
      
      // if not authenticated redirect to login and prevent navigation
      if (!document.cookie.includes('authenticated=true')) {
        if (location.pathname !== '/login') location.href = '/login';
        preventNavigation(true);
        // preventNavigation(false);
      }
            
          
Main application Styles
app.css
Optional: Will bundle and minify into a single file
            
      @import url('./other.css');
    
      body {
        background-color: white;
      }
            
          
Page
page.js and page.html
            
      import { Component } from '@webformula/core';
      import html from './page.html'; // automatically bundles
      
      export default class extends Component {
        static pageTitle = 'Page'; // html page title
        static html = html; // hook up imported html. Supports template literals (${this.someVar})
    
        someVar = 'Some var';
        clickIt_bound = this.clickIt.bind(this);
        userInput;
        
        
        constructor() {
          super();
        }
        
        connectedCallback() {
          // called on element hookup to dome. May not be rendered yet
        
          this.userInput = 'some user input';
          console.log(this.urlParameters); // { id: 'value' }
          console.log(this.searchParameters); // { id: 'value' }
        }
        
        disconnectedCallback() {
          // called on element removal
        }
        
        // not called on initial render
        beforeRender() {
          // Do work before render
        }
        
        afterEnder() {
          // Do work after render
          this.querySelector('#event-listener-button').addEventListener('click', this.clickIt_bound);
        }
        
        // look below to how it is invoked on a button
        clickIt() {
          console.log('clicked it!');
        }
        
        // look below to how it is invoked on a button
        changeValueAndRender() {
          this.someVar = 'Re-rendered';
          this.render(); // initial render is automatic
        }
        
        /**
        * If not importing html you can use this template method.
        * Imported html also supports template literals (undefined)
        */
        template() {
          return /*html*/`
        <div>Page Content</div>
        <div>${this.someVar}</div>
        
        <!-- escape html input -->
        <div>${this.escape(this.userInput)}</div>
        
        <!-- "page" will reference the current page class -->
        <button onclick="page.clickIt()">Click Method</button>
        <button id="event-listener-button">Event listener</button>
        <button onclick="page.changeValueAndRender()">Change value and render</button>
      `;
        }
      }
            
          
Build app
build.js
No need for webpack or other bundlers. ESbuild is packed in and pre configured.
Build config
            
      import build from '@webformula/core/build';
      
      /**
      * runs dev server by default on port 3000 with livereload
      * basedir defaults to 'app/'
      */
      build({ basedir: 'app/' });
          
        
Run commands
          
      # Development run
      node build.js
    
      # Development run with watch to enable livereload
      node --watch-path=./app build.js
    
      # Production run. minifies, gzips, and writes files
      NODE_ENV=production node build.js
      
            
          
Serve app
server.js
Handle routing and file serving with middleware. GZIP compression is automatically handled.
Serve config
Native server
            
      import { createServer } from 'node:http';
      import { middlewareNode } from '@webformula/core/middleware';
      
      const middleware = middlewareNode({
        basedir: 'docs/',
        outdir: 'dist/',
        copyFiles: [
          { from: 'docs/favicon.ico', to: 'dist/' }
        ]
      });
      
      createServer(async (req, res) => {
      const handled = await middleware(req, res);
        if (handled === true) return;
        
        // Do other stuff
      }).listen(3000);
            
          
Express server
            
      import express from 'express';
      import { middlewareExpress } from '@webformula/core/middleware';
      
      const app = express();
      app.use(middlewareExpress({
        basedir: 'docs/',
        outdir: 'dist/',
        copyFiles: [
          { from: 'docs/favicon.ico', to: 'dist/' }
        ]
      }));
      app.use(express.static('./docs'));
      app.listen(3000);
            
          
Livereload
            
      # Simply use node --watch to enable livereload
      node --watch-path=./src --watch-path=./docs server.js
            
          
Devtools
A small set of helper functions
            
      // Look at variable binding info for current page
      window.getBoundVariables();
      
      // View current page template string
      window.getPageTemplate();
      
      // Get all pages route details
      window.getRoutes();