@plurid/elementql-client-react v0.0.0-1
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-serveror
yarn add @plurid/elementql-serverStart
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: OverwriteNameGo
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.yamlconfiguration 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/JSONrequest, - instantiating an
ElementQLClientwith theURLfor theElementQLserver endpoint, - and making the request with the
useEffect,useStatestandardReacthooks, - or with the
useElementQLcustom 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-react • react client
@plurid/elementql-express • express middleware
@plurid/elementql-server • NodeJS server
@plurid/elementql-server • Go server
@plurid/elementql-specification • specification
@plurid/elementql-org • documentation
Codeophon
ElementQL Client React
Usage
import elementQLClientReact, {
elementQL
} from '@plurid/elementql-client-react';
const elementQLClient = elementQLClientReact({
url: 'https://api.example.com/elementql',
});
const DIV = elementQL`
import {
<Div>
}
`;
// gets a React Function Component
const Div = await elementQL.get(DIV);@plurid/elementql-client-react uses @plurid/elementql-client under the hood to inject the script/style
and returns window.elementQL.Div which is a React function component
the React component should be exported wrapped around a HoC withElementQL which will make the component available on window
ElementQL Context
import {
ElementQL,
} from '@plurid/elementql-client-react';
const SomeProvidedElement = () => (
<ElementQL.Provider
elements={{
SomeElement: () => (<div>some element</div>),
}}
>
<ElementQL.Consumer>
{(context) => {
const SomeElement = context?.getElement('SomeElement');
if (!SomeElement) {
return (<></>);
}
return (<SomeElement />);
}}
</ElementQL.Consumer>
</ElementQL.Provider>
);