0.0.0-0 • Published 3 years ago

@plurid/elementql-server v0.0.0-0

Weekly downloads
-
License
SEE LICENSE IN LI...
Repository
github
Last release
3 years ago

ElementQL is a query language specification and implementation to query a server for Web Elements source code in order to render them on the client.

Contents

Description

Current State

Consider the following Web Element which uses React

const HelloElementQL = () => {
    return React.createElement('div', null, 'Hello from ElementQL');
}

When embedded into a standard React rendering process, the HelloElementQL functional element will generate a div containing the text Hello from ElementQL.

The normal manner of sending the element to the browser is by packing it up into an Application, in a large JavaScript index.js file, which gets attached to a index.html with a script tag and then gets sent by the server to the client.

ElementQL Proposal

The manner proposed by ElementQL is to let the client request only the required elements at runtime from a server and receive only the particular element-specific module.

Usage

Server

NodeJS

Install

The NodeJS server can be installed running the command

npm install @plurid/elementql-server

or

yarn add @plurid/elementql-server
Start

The simplest ElementQL server requires only to be started, the elements will be served from the default ./elements path

// server.js
import ElementQLServer from '@plurid/elementql-server';


const server = new ElementQLServer();

server.start();

The server will then accept requests on the http://localhost:21100/elementql URL for the elements in the ./elements directory.

Elements

The ./elements directory has a structure of folders with element-specific files: .js, .jsx, .ts, .tsx, or .css. For example

.
|- server.js
|- elements
|   |- HelloElementQL
|   |   |- index.js
|   |-
|-
Options

The ElementQLServer Object can receive an options object

import {
    ElementQLServerOptions,
} from '@plurid/elementql-server';


/** defaults */
const options: ElementQLServerOptions = {
    protocol: 'https',                          /** default for production; for development: `'http'` */
    domain: '',                                 /** the domain for the server, e.g. example.com */
                                                /** will be used to resolve elements relative and library imports */
    port: 21100,

    rootDirectory: process.cwd(),
    buildDirectory: 'build',                    /** relative to the root directory */
    nodeModulesDirectory: 'node_modules',       /** relative to the root directory */
    elementqlDirectory: '.elementql',           /** relative to the build directory */
    transpilesDirectory: 'transpiles',          /** relative to the elementql directory */

    elementsDirectories: [                      /**/
        'elements',                             /** relative to the build directory */
    ],                                          /**/
    libraries: {},
    endpoint: '/elementql',
    allowOrigin: ['*'],
    allowHeaders: ['*'],
    plugins: [                                  /**/
        'minify',                               /** default for production; for development: `[]` */
    ],                                          /**/

    verbose: true,
    open: true,
    playground: false,
    playgroundEndpoint: '/playground',

    store: null,
    metadataFilename: 'metadata.json',
};
Requests

In production, an ElementQL Client is recommended. In development/testing, the requests for elements can be made using the POST method with a Content-Type header of application/json or application/elementql. For example

JSON

curl http://localhost:21100/elementql \
    -H "Content-Type: application/json" \
    -v --data '{"elements":[{"name":"HelloElementQL"}]}'

ElementQL

curl http://localhost:21100/elementql \
    -H "Content-Type: application/elementql" \
    -v --data 'elements{HelloElementQL}'
Metadata

In each element directory there can be an elementql.yaml file with metadata specific to the element

# the element name derived from the directory name will be overwrriten with `OverwriteName`
name: OverwriteName

Go

The elementql-server for Go is a go 1.14 module.

Python

Client

React

Considering the standard React application, using ElementQL involves

  • creating an elementql.yaml configuration file,
---
globals:
  react: React
  react-dom: ReactDOM
origins:
  elementql: http://localhost:21100/elementql
  application: http://localhost:8005
bootloader: './source/index.js'
entry: './app/index.js'
  • creating the service-worker,
const elementQLServiceWorker = './node_modules/@plurid/elementql/distribution/service-worker.js';


importScripts(elementQLServiceWorker);
  • creating and running the metabootloader,
const metabootloader = require('@plurid/elementql/distribution/metabootloader').default;


metabootloader();
  • creating and running useLibraries
const {
    libraries,
    useLibraries,
} = require('@plurid/elementql');



const usedLibraries = {
    react: libraries.react,
    reactDom: libraries.reactDom,
};

const buildDirectory = 'build';


useLibraries({
    libraries: usedLibraries,
    buildDirectory,
});
  • defining an ElementQL/JSON request,
  • instantiating an ElementQLClient with the URL for the ElementQL server endpoint,
  • and making the request with the useEffect, useState standard React hooks,
  • or with the useElementQL custom hook.
import React, {
    useEffect,
    useState,
} from 'react';

import ElementQLClientReact, {
    useElementQL,
} from '@plurid/elementql-client-react';



const elementQLClient = new ElementQLClientReact({
    url: 'http://localhost:21100/elementql',
});

const ElementQLJSONRequest = {
    elements: [
        {
            name: 'HelloElementQL',
        },
    ],
};


const AppWithHook: React.FC<any> = () => {
     const Elements = useElementQL(
        elementQLClient,
        ElementQLJSONRequest,
        'json',
    );

    return (
        <>
            {Elements && (
                <Elements.HelloElementQL />
            )}
        </>
    );
}


const App: React.FC<any> = () => {
    const [Elements, setElements] = useState<any>();

    useEffect(() => {
        let mounted = true;

        const fetchElements = async () => {
            const {
                status,
                Elements,
            }: any = await elementQLClient.get(
                ElementQLJSONRequest,
                'json',
            );

            if (!status || !mounted) {
                return;
            }

            setElements(Elements);
        }

        fetchElements();

        return () => {
            mounted = false;
        }
    }, []);

    return (
        <>
            {Elements && (
                <Elements.HelloElementQL />
            )}
        </>
    );
}


export default App;

Plugins

Babel

Uses Babel to transpile .js and .jsx element files.

TypeScript

Uses TypeScript to transpile .ts and .tsx element files.

Minify

Uses Terser to minify the element files.

Packages

@plurid/elementql • base

@plurid/elementql-client

@plurid/elementql-client-reactreact client

@plurid/elementql-expressexpress middleware

@plurid/elementql-parser

@plurid/elementql-server • NodeJS server

@plurid/elementql-server • Go server

@plurid/elementql-specification • specification

@plurid/elementql-org • documentation

Codeophon


ElementQL Server

the server reads the element files (script, style, templates) defined and serves on request

define elements schemas

define elements resolvers

get the files of the elements

get a request for an element (or elements)

compile the element(s) to client-specific browser -- no more duplicated code served to client

serve element(s)