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
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
npminstallable packages. - And creating a mirror for
npmfor converting and serving all packages toesm. 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
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@aa99dd13a8c20277795a17204d2f6dfba52e0737Frameworks 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.
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.
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 AppFor 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-httpConfiguring 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-systemModules 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.
Comments
No comments yet. Be the first to share your thoughts.