Neoteric Plumbing Mishap

    js-in-json

    0.2.1 • Public • Published

    JS in JSON

    A server side agnostic way to stream JavaScript, ideal for:

    • inline hydration
    • network free ad-hoc dependencies
    • bootstrap on demand
    • libraries on demand
    • one JSON file to rule all SSR cases

    The Session utility is currently available for:


    An "islands friendly" approach to Server Side Rendering able to produce stream-able JS on demand, via any programming language, through a single JSON bundle file instrumented to flush() any script, after optional transpilation and/or minification.

    The produced output can be also pre-generated and served as static content, with the advantages that js-in-json bundles require zero network activity: forget round-trips, thousand ESM requests per library or project, and simply provide all it's needed right on the page.

    // a basic serving example
    const {JSinJSON} = require('js-in-json');
    
    // see ## Options
    const {options} = require('./js-in-json-options.js');
    
    const islands = JSinJSON(options);
    // islands.save(); when needed to create the JSON bundle
    
    http.createServer((req, res) => {
      // see ## Session
      const js = islands.session();
      js.add('Main');
      res.writeHead(200, {'content-type': 'text/html'});
      res.write(`
        <!doctype html>
        <script src="//external.cdn.js"></script>
        <script>${js.flush()}</script>
        <body>
          <div class="component"></div>
          <script>${js.add('UI/component').flush()}</script>
        </body>
      `.trim());
      js.add('Footer');
      if (global.condition) {
        js.add('SpecialCondition');
        res.write(`<script>${js.flush()}</script>`);
      }
      res.end();
    });

    Session

    A js-in-json session can be initialized right away via js-in-json/session exported Session class, or through the main JSinJSON(options).session() utility.

    A session created via JSinJSON optionally accepts a JSON bundle, retrieved from options, if not provided, and it exposes 2 methods:

    • add("ModuleName") to flush its content only once and, if repeatedly added, and available, bootstrap its code
    • flush() to return all modules and their dependencies previously added and, if available, their code to bootstrap

    In order to have a session, a JSON bundle must be created.

    Options

    Following the object literal with all its defaults that can be passed to the JSinJSON(options) export.

    const {save, session} = JSinJSON({
    
      // TOP LEVEL CONFIG ONLY
    
      // MANDATORY
      // the root folder from which each `input` is retrieved
      // used to resolve the optional output, if relative to this folder
      root: '/full/project/root/folder'
    
      // OPTIONAL
      // where to store the resulting JSON cache usable via JSinJSON.session(cache)
      // if omitted, the cache is still processed and returned
      output: './bundle.json',
      // the global context used to attach the `require` like function
      global: 'self',
      // the `require` like unique function name, automatically generated,
      // and it's different per each saved JSON (hint: don't specify it)
      prefix: '_uid',
    
    
      // OPTIONAL EXTRAS: CAN BE OVERWRITTEN PER EACH MODULE
      // use Babel transformer to target @babel/preset-env
      babel: true,
      // use terser to minify produced code
      minify: true,
      // transform specific bare imports into other imports, it's {} by default
      // see: rollup-plugin-includepaths
      replace: {
        // example: replace CE polyfill with an empty file
        '@ungap/custom-elements': './empty.js'
      },
      // executed each time a JSinJSON.session.flush() happens
      // no matter which module has been added to the stack
      // it's missing/no-op by default and it has no access
      // to the outer scope of this file (it's serialized as function)
      code(require) {
        // each code receives the `require` like function
        const {upgradeAll} = require('Bootstrap');
        upgradeAll();
      },
      // an object literal to define all modules flushed in the page
      // whenever any of these is needed
      modules: {
        // the module name available via the `require` like function
        Bootstrap: {
          // MANDATORY
          // the ESM entry point for this module
          input: './bootstrap.js',
    
          // OPTIONAL: overwrite top level options per each module
          // don't transform and/or don't minify
          babel: false,
          minify: false,
          // will be merged with the top level
          replace: {'other': './file.js'},
          // don't flush anything when injected
          code: null
        },
    
        // other module example
        Login: {
          input: './login.js',
          code() {
            document.documentElement.classList.add('wait');
            fetch('/login/challenge').then(b => b.json).then(result => {
              self.challenge = result;
              document.documentElement.classList.remove('wait');
            });
          }
        }
      }
    });

    Options Rules / Limitations

    • the root should better be a fully qualified path, instead of relative
    • the code is always transformed with @babel/preset-env target
    • the code cannot be asynchronous
    • modules cannot have _ as name prefix, that's reserved for internal resolutions
    • modules should have non-npm modules names, to avoid conflicts/clashing with imports
    • modules can be capitalized

    Install

    npm i js-in-json

    DownloadsWeekly Downloads

    3

    Version

    0.2.1

    License

    ISC

    Unpacked Size

    102 kB

    Total Files

    19

    Last publish

    Collaborators

    • webreflection