This is an example how to set up a repository that builds code which can be consumed in Framer. It builds standard JavaScript into ES Modules that you can both use locally for development or to deploy to any http server for distribution across your team or the internet.
yarn run serve
This runs a local web server with the built code.yarn run build
This builds the code indist
.
All the magic is in the esmbuild
folder. Contributions are welcome.
- Built on
esbuild
for speed and to support JavaScript, TypeScript and JSX. - Custom plugin to handle ESM imports and rewrite local import paths.
- CSS Modules plugin to support writing css scoped modules.
- GitHub Workflow to deploy versioned code on GitHub pages.
Start the development server with:
yarn run serve
Open Framer, create a code file and paste the following:
import { addPropertyControls, ControlType } from "framer"
import { Button as ImportedButton } from "http://127.0.0.1:8000/index.js"
export const Button: React.ComponentType = ImportedButton
addPropertyControls(Button, {
title: {
title: "Title",
type: ControlType.String,
defaultValue: "Title",
},
})
You can now add your component to the canvas and configure it using the defined propertyControls
. This setup assumes you want to define them only on the Framer side (keeping your code clean) but you can also keep them in the original source.
The imported esm gets cached quite agressively, if you want to make sure you see the latest version you can add a random value to the imported url line:
import { Button } from "http://127.0.0.1:8001/index.js?123"
If you forget to start your local server, your component will render with:
Error in <name>.tsx Failed to Fetch
Once you are ready to deploy your code, it should be uploaded to an https endpoint with a versioned url. We have set up a Workflow to build the code and deploy to GitHub Pages. To ship a next version you simply type:
yarn run deploy
You'll have to type a new version (let's say 1.0.4
), and soon the code will be deployed to: https://framer.github.io/example-framer-esm-setup/[email protected]/index.js. You can now update your imports to the production url and you'll get the exact same result:
import { Button } from "https://framer.github.io/example-framer-esm-setup/[email protected]/index.js"
It's very important to version your code, so endpoints stay stable. To move to a new version, you simply update the import urls wherever you need.
You can use the default esbuild css importer, or you can use a plugin to use css modules, that optionally auto inserts the css as a <style>
tag (as configured).
The plugin.esm.js
makes sure that your local file imports are translated to esm imports. In the example configurations it works as follows:
import React from "react"
import ReactDOM from "react-dom"
import Framer from "framer"
import motion from "framer-motion"
Externals work like externals, so they can be picked up by an import map. In Framer we defined specific ones in the current import map, so we marked them as externals in the setup here.
import * as _ from "lodash"
node_modules
work like you would expect. You can just install them with yarn
and they'll be inlined in the module that imports them.
import * as _ from "https://ga.jspm.io/npm:[email protected]/index.js"
Url imports will just be kept intact so you can do non local esm imports.
import { Button } from "./Button"
Local esm imports will be rewritten to include the file extension:
import { Button } from "./Button.js"
Private code: you should keep your source private, but not your built code. Make sure to enable minify
in the esmbuild.js
script to minify your code.
Assets: you can host your assets (images, movies) anywhere you like and just use the full urls to use them in your components.
Auto refresh: you currently have to manually reload your components to see changes in your development code. It should be doable to make an esbuild
plugin that inserts a snippet to auto reload after changes. Contributions are welcome.