teleporthq
Platform
Solutions
Integrations
Resources
Product

Cloud components in TeleportHQ

Cloud components in TeleportHQ

Today we want to take some time to talk to you about a new functionality that we've added to TeleportHQ: Cloud components.

Introduction to Cloud components

The Cloud components feature allows you to import components created visually in TeleportHQ in other dev environments as well as other TeleportHQ projects. The components are compatible with React and Next.js and work by importing them directly from a CDN instead of using a traditional package manager.

Let's go through some of the details and work that went into making this feature possible.

ES-Modules

Each module is a piece of code that is executed once it is loaded.

exploringjs.com
es-modules-a-cartoon-deep-dive
es-modules-in-browsers
using-es-modules

Browser Support

Major browsers have a base-line support for es-modules, support for these modules is at 94.45%.

Some features and language syntaxes like dynamic-import and import-maps are not supported fully yet. We can solve this my using shims. More about shimming can be found here

caniuse.com/es6-module

es-module-shims

Node-modules vs CDN

  • Modules can be cached independently which improves load times of subsequent visits.
  • Each module is individually served to the users using a CDN.
  • Transpilation, polyfilling and optimizations for the vendor modules happens ahead of time.

We have a handful of providers, which serve all the packages from npm

JSPM, skypack, esm.sh deno.land.

These module-cdn providers, traspile the packages, converts them to esm when needed (in the case of cjs). And serve these modules so users can directly use them in browsers, with production optimizations.

In a stanrd node_modules mode of development, we need to configure our bundlers, to transpile, polyfill, or even provide interoperability now.

This happens every time, when we build our projects. Imagine the time, users can save from eliminating these steps, during the time of development. And the time can be saved inside CI pipelines.

More about the CDN's in their respective pages

module-cdn-semantics-jspm
skypack-cdn/api-reference

ES Modules from TeleportHQ studio

At TeleportHQ, we are on and off this topic with research for a while. The current level of browsers support, and bundlers starting to adopt these workflows makes ot a best fit.

Some of our past experiments include

  • Serving components from the studio as npm installable packages.
  • And creating a mirror for npm for converting and serving all packages to esm. You can find more of it here

Modules in TeleportHQ uses bare-module-specifiers for package imports. This gives control to the end users from where the external-dependencies can e served. So, at any instance, these modules load only code that is generated from the studio and code-generators. This helps users to ship with confidence and security, as users can choose from where the external dependencies are loaded.

You can serve the external dependencies using node_modules and cdn as well. More about these in the worflows.

Workflows

There are 3 different types of workflows for users to choose from, while using modules from TeleportHQ.

Optimizations from the studio

All the Modules are:

  • Transpiled.
  • Linked between one-another.
  • Served from a global CDN.
  • Version locked.

When modules are nested, we don't bundle them. Instead it links the modules using imports.

Every project is mainly divided into three categories if modules

  • Styles
  • Globals and fonts
  • Components
Module categories for a project created in TeleportHQ studio

Styles

In studio we can define styles in multiple ways, css-classes, typography and design tokens and layout tokens. All of these are combined into a es-module with the name styles. And each time the module changes, the changes are versioned.

import {
  projectStyleVariants,
  TOKENS,
} from 'https://jscdn.teleporthq.io/new-project-dqpb/style.js@35ff99074a6491e551432d47881ebdce23a21cef'

All the styling is maintained using styled-components and styled-system. But, users will be able to generated modules using react-jss too in the coming days.

Style module exports TOKENS and projectStyleVariants. The styles module can be used independently inside any project. And so, uses can maintain their design tokens even more closer to the design inside the studio.

Globals and fonts

In studio users can define the globals like, fonts and seo. Studio is designned to help users build full scale project. All the globals that we use in a project are astracted into globals module.

import Globals from 'https://jscdn.teleporthq.io/new-project-dqpb/globals.js@646826692c3ac0769586600c4719b2024c8a399a'

All the components inherit the Globals everytime a module is generated. A typical component looks like

import React from 'react'
import Globals from 'https://jscdn.teleporthq.io/new-project-dqpb/globals.js@646826692c3ac0769586600c4719b2024c8a399a';

const App = () =>. {
    return (
        <Fragment>
            <Globals />
            {/* ... */}
        </Fragment>    
    )
}

Components

Every component inside the studio is generated individually into a module. And the components are linked together depending on the usage.

By splitting all the modules independently, helps in performance. First, the module content is not duplicated.

Second, when the module is used multiple times they are served from cache.

As, modules can be imported multiple times. But they are only executed once.

import Header from 'https://jscdn.teleporthq.io/new-project-dqpb/header.js@aa99dd13a8c20277795a17204d2f6dfba52e0737'

A module's version is updated only when the component, or any of modules that the component is depend on changes.

The @version of a module changes when globals, styles or the component itself changes.

Assets

In studio we can use, multimedia while designing our components. The assets which are used, are also served from the CDN.

Source-maps

You can get source-map for any module, by changing the extension at the end.

https://jscdn.teleporthq.io/new-project-dqpb/header.map@aa99dd13a8c20277795a17204d2f6dfba52e0737

Frameworks and component flavours

While designing components in the studio, users can use routeLinks, seo-tags and many framework dependent features. To support these, we allow users to choose the target environment they are using the modules. As in most of cient-side react-apps, we use react-router and for NextJS we use next/link. And it's the same for react-helmet vs next/head.

These es-modules are generated using our open-source code generators. Which are availale at GitHub. And we plan to bring the same support for other frameworks and even style-flavour combinations. Like, React + React-JSS, Next + React-JSS etc.

Cloud components and import-maps

With the introduction of es-modules, now we can organize our code per module. And import any modules when needed, and we have even more control on which modules loaded at runtime using Dynamic Imports.

Remember in good olden days, we used to load JS into the browser using script tag. And we had a very little control over which loads first. And with scripts depending on one another. Properly, arranging the sequence became a huge part in the JavaScript development.

And then the introduction of bundlers, task-runners to take care of this manual work. Import-maps, provide a great way to develop applications without a whole bundler, resolver setup. And allows users, to directly use "bare-module-specifiers". Which means users can write

import { useState } from 'react'

And import-map will take care of resolving the react from the source provided in it.

From our announcement of es-modules from Cloud components with teleportHQ. You can use all components, styles and tokens as individual modules. And since, the modules from TeleportHQ uses "bare-module-specifier" we need to use an import-map to notify the browser from where the external dependencies need to be resolved.

ES-Modules without bare-module-specifiers

Let's load react-dom module from skypack. We can see the external dependencies of the package are also imported using URLs.

<iframe height="300" style="width: 100%;" scrolling="no" title="Skypack Example" src="https://codepen.io/jkrishna/embed/preview/vYWEPZQ?default-tab=js" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/jkrishna/pen/vYWEPZQ">
  Skypack Example</a> by Jaya Krishna (<a href="https://codepen.io/jkrishna">@jkrishna</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>

You can see, the react-dom package in return uses object-assign and scheduler internally and loads these from another unique pre-mapped URLs.

js
import aa from "/-/react@v17.0.1-yH0aYV1FOvoIPeKBbHxg/dist=es2020,mode=imports/optimized/react.js";
import m from "/-/object-assign@v4.1.1-LbCnB3r2y2yFmhmiCfPn/dist=es2020,mode=imports/optimized/object-assign.js";
import r from "/-/scheduler@v0.20.2-PAU9F1YosUNPKr7V4s0j/dist=es2020,mode=imports/optimized/scheduler.js";

Module from TeleportHQ

Modules from TeleportHQ uses a combination of bare-module-specifiers with pre-mapped unique URLs. So the users can take care of loading dependencies and all the studio dependent modules are loaded automatically.

A typical cloud-component has the following imports.

jsx
import React from 'react';
import { variant } from 'styled-system';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import Globals from 'https://jscdn.teleporthq.io/new-project-dqpb/globals.js@646826692c3ac0769586600c4719b2024c8a399a';
import { projectStyleVariants, TOKENS } from 'https://jscdn.teleporthq.io/new-project-dqpb/style.js@35ff99074a6491e551432d47881ebdce23a21cef';

We can generate a import-map using jspm which is available online, or as a npm package. generator.jspm.io

You can enter, all the dependencies that you are being used. In our case, react, react-dom, styled-components and prop-types and styled-system. You can use this url, the generator loads and creates a import-map with all these modules.

generator.jspm.io

Here is a pre-configured template for using.

<iframe height="500" style="width: 100%;" scrolling="no" title="teleportHQ - jspm - template" src="https://codepen.io/jkrishna/embed/VwMaWaN?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/jkrishna/pen/VwMaWaN">
  teleportHQ - jspm - template</a> by Jaya Krishna (<a href="https://codepen.io/jkrishna">@jkrishna</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>

Templates from Codesandbox and Codepen.

Codepen
Codesandbox

You can find even more about import-maps at:

Cloud components with Next.JS

If you are new to cloud-components, you should check our quick post on it. It's a quick read and can be found here

URL Imports with Next.JS

TeleportHQ likes Next JS from it's inception, for the ease of development, deployments and scalability with a super-charged framework using React.

From v@12 , Next-JS introduced a new feature called urlImports for loading JS modules from remote sources. Which can completely eliminate the step of bundling and transpiling JS modules every time. We can load a module from CDN and use it directly inside our projects.

URL Imports + TeleportHQ

You can generate a unique module link, by right clicking on any component from the components list in studio. And the module can be directly used in any Next-JS project.

jsx
import Card from 'https://jscdn.teleporthq.io/new-project-68d4/card.js@be57bcf81f65fd2541ccd1a2e69a02b3e4c88a84'

const App = () => {
    return (
    <div>
       <Card />
    </div>
  )
}

export default App

For setting up your projects to use components from TeleportHQ. You can visit https://github.com/teleporthq/nextjs-http and use the template for starting new projects.

npx degit https://github.com/teleporthq/nextjs-http

Configuring existing projects

For configuring any existing NextJS projects, your NextJS version should be 12 at minimum.

Open your next.config.js. And add https://jscdn.teleporthq.io to your urlImports section. This allows Next-JS to import modules only from specific domains. This disables executing js from any unknown domains. You can read more about it url-imports-security-model.

js
module.exports = {
  reactStrictMode: true,
  experimental: {
    urlImports: ['https://jscdn.teleporthq.io']
  }
}

Now add styled-components and styled-system to your project. This can be done using

bash
npm install styled-components styled-system

Modules from TeleportHQ uses these two packages to define styling and style-variants, design tokens in a project. And all the imports for external-modules use bare-module-specifiers. So, users can serve those dependencies according to their liking.

Next you need to tweak your next.config.js. We need to alias in our next.config.js to use esm version of styled-components. More about this step, can be found here.

After making the changes, your next.config.js looks something similar to this.

js
module.exports = {
  reactStrictMode: true,
  webpack: (config) => {
    config.resolve.alias = {
      ...config.resolve.alias,
      'styled-components': require.resolve('./node_modules/styled-components/dist/styled-components.esm.js'),
    }

    return config
  },
  experimental: {
    styledComponents: true,
    urlImports: ['https://jscdn.teleporthq.io']
  }
}

You are all set, now run ...

bash
npm run dev

... and your project should be loading at - http://localhost:3000 🚀

Miscellaneous

NextJS creates a next.lock with all the modules that are loaded dynamically from CDN, except the modules that are served with Cache-Control: no-cache. You can read more about it here.

Product

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment

Your email is never shown publicly.
Comments are reviewed before they appear.