Technical Documentation: plasmicapp/plasmic
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (README.md)
Plasmic
The open-source visual builder for your codebase.
Quick links
See Plasmic in action
Vercel marketing page: https://youtu.be/itvbmgLZvcM (live app: https://vercel-workflow.vercel.app)
Apple.com: https://apple.plasmic.run
Shopify headless storefront: https://commerce.plasmic.run
Twitter clone: https://youtu.be/rpdjrFuVMog (live app: https://twitter.plasmic.run)
Service desk app: https://youtu.be/rYqSpUEJSTw (live app: https://tickets.plasmic.run)
Interview with Lee Robinson, Plasmic as a visual CMS: https://www.youtube.com/watch?v=pcVzNR6FBAQ
What is Plasmic?
Plasmic is a visual builder for the web.
It enables rapidly designing and building applications and websites--code optional.
Main use cases:
Content management: let marketing drag/drop your React components to build landing pages in your Next.js website, with design guardrails
Applications: let developers and technical users quickly build internal tools, client portals, and business software
Website builder and design tool that doesnโt limit you to some built-in ecommerce platform, CMS, or hosting
Plasmic is powerful, with a deep feature set that scales to complex projects.
And with codebase integration, it removes the ceiling typically associated with low-code tools.
What makes Plasmic special?
Plasmic combines some seemingly disparate genres:
- Webflow, Wordpress and other site builders
- Retool and other tool builders
- Glide and no-code app builders
- Contentful and other CMSes
Today these are different tools to specialize in, but the line between, say, a website and an application is blurry (consider an ecommerce storefront with user logins). With the right foundations, we think these can be unifiedโPlasmicโs UI can adapt to different levels of control for different personas/tasks.
But more importantly, unlike existing tools, Plasmic integrates with codebases. This is critical to making low-code scale past the complexity ceiling that all such tools (including Plasmic) have. You can drag and drop existing complex React components, and you can visually create new UIs/components within traditionally-coded applications, seamlessly weaving code and no-code.
Some feature highlights:
- Full design freedom and speedy modern design tool UX.
- Integrate with codebases to drag/drop existing React components, publish screens into existing applications, and extend/customize Plasmic Studio.
- Create rich stateful interactions and behavior.
- Connect with arbitrary data source and backend integrations.
- Powerful abstractions like components, variants, slots, composable state management, and more that promote composition and let you build and maintain at scale.
- Customizable headless design system components powered by react-aria.
- Content creator mode: give specific collaborators a more simplified editing experience with design guardrails.
- Open integrations: choose your own CMS, ecommerce platform, hosting provider, and more.
- Deep collaboration with multiplayer, branching, cross-project imports, and multi-workspace organizations.
- Import designs from Figma, translating its proprietary vector document format into DOM/CSS.
- Page performance and high-quality codegen. Supports static site generation, automatic image optimization, layout shift reduction, and more.
- Deploy/host/export anywhere, including Vercel, Netlify, or any hosting provider.
- End-user auth and permissions, including RBAC and user-scoped permissions.
- Open-source platform that you can always fork and control.
Learn more on our website and our docs. Or check out comparisons of Plasmic vs other tools.
How do I integrate Plasmic as a CMS?
This is one popular use case of Plasmic.
Step 1. Install Plasmic into your codebase (exact package depends on your framework).
npm install @plasmicapp/loader-nextjsStep 2 (optional). Make components from your app or design system available for drag-and-drop in the visual editor:
// Take any component from your app or design system...
export default function HeroSection({ children }) {
return <div className="hero-section">{children}</div>;
}
// ...and make it available for drag-and-drop, along with any props you want to
// expose.
PLASMIC.registerComponent(HeroSection, {
props: {
children: "slot",
},
});Step 3. Add placeholders that render pages/components made in the visual editor anywhere in your app:
// pages/index.tsx
import {
PlasmicComponent,
PlasmicRootProvider,
} from "@plasmicapp/loader-nextjs";
import { PLASMIC } from "../plasmic-init";
// Here we fetch dynamically on the client, but you can also fetch and render
// components server-side in SSG/SSR frameworks, such as via getStaticProps
// in Next.js.
export default function IndexPage() {
return (
<PlasmicRootProvider plasmic={PLASMIC}>
<PlasmicComponent component="Summer22LandingPage" />
</PlasmicRootProvider>
);
}Step 4. Non-developers (or developers!) can now create new pages, sections, or components that ship directly into the app/website.
Step 5. When you hit Publish, changes get picked up via webhooks that trigger rebuilds,
or more specific mechanisms such as incremental static revalidation or dynamic fetching from the Plasmic CDN.
Who uses Plasmic?
Plasmic is used by companies ranging from Fortune 500s to boutique brands to solo makers.
It's used for websites ranging from headless commerce storefronts to marketing websites to logged-in app content.
Check out the Case Studies and Community Showcase.
How does Plasmic work?
How codebase integration works
Note: you do not need to integrate Plasmic with a codebase.
This is core to using Plasmic as a CMS, but you can build complete apps and websites without this, entirely within Plasmic.
Read the full technical overview.
Bring your own React components
You can register your own arbitrary custom React components for use as building blocks within Plasmic Studio.
Learn more about code components.
Codegen
Besides the Headless API, you can also generate React code into your codebase.
This is a powerful way to use Plasmic as a UI builder for creating rich interactive web applicationsโone example of this is Plasmic Studio itself.
See the application development tutorials to learn more.
Note on versioning
One common issue we see is mismatched or duplicate versions of packages.
@plasmicapp packages can depend on each other.
Each package always has an exact version of its @plasmicapp dependencies.
This is because we want to ensure that all packages are always in sync, and that we don't end up with a mismatched set of packages.
Packages like @plasmicapp/host must also be deduped, since functionality such as registerComponent make use of globals and side effects, so with multiple versions you could end up using the wrong "instance" of this package.
Additionally, types can be tightly coupled across multiple packages.
Unfortunately, npm and yarn make it easy for you to end up with mismatched versions and duplicate versions of packages.
Use the npm list command to ensure that you have unique deduped versions of packages.
Furthermore, issues can be "sticky," since npm/yarn are stateful.
At times, you may need to rely on npm dedupe, or removing and reinstalling Plasmic packages (including @plasmicpkgs packages), resetting package-lock.json/yarn.lock, in order to unwedge npm/yarn.
@plasmicpkgs (the built-in code component packages) have @plasmicapp packages as peer dependencies,
and these specify ranges rather than exact versions--this is to offer some flexibility for developers to use the core package versions they need, while still using @plasmicpkgs.
Note: exact versioning does not imply that every package increments versions for every release.
Packages are only incremented if they or their dependencies have changed.
Incrementing versions is done automatically when our deployment scripts run lerna version patch --exact...,
which detects whether a package has changed since its last git-tagged release.
Internal dependencies and devDependencies are declared as workspace:*, which pnpm publish replaces with the exact version at pack time.
Contributing ๐
Please see CONTRIBUTING.md.
Get help and join our community
Our docs and our community forum and Slack with 3000+ members are the best places to get help with Plasmic.
For support from the Plasmic team, please use the forum.
The forum is also easily searchable for all previously asked questions and discussions.
Both the docs and forum are indexed by search engines!
Search both by including โplasmicโ in your query.
License
All content outside of platform/ is licensed under the MIT license--see LICENSE.md.
platform/ is licensed under the AGPL--see LICENSE.platform.md.
Contributors โค๏ธ
Thanks to all the people who make Plasmic!
Contributing Platform 00 Getting Started (`docs/contributing/platform/00-getting-started.md`)
Developing Plasmic Studio: getting started
Database setup
Plasmic uses PostgreSQL (v15) as a database. We highly recommend setting postgres through docker (see docker-compose.yml for details). If you follow the Docker setup guide -- database will be created for you automatically.
If you prefer the manual application set up just run docker-compose up -d --no-deps plasmic-db in your terminal to build and launch the postgresql instance.
OS-specific instructions
Mac OS X
This section applies only if you install postgres manually, not through docker.
Update the version numbers for Postgresql in the following depending on what's latest!
{ sed 's/#.*//' | while read line; do sudo port install -b $line; done ; } << "EOF"
curl-ca-bundle
postgresql15
postgresql15-server
hadolint # for Dockerfile checking
EOF
# Follow the instructions printed during the postgresql-server installation:
sudo port select postgresql postgresql15
sudo mkdir -p /opt/local/var/db/postgresql15/defaultdb
sudo chown postgres:postgres /opt/local/var/db/postgresql15/defaultdb
sudo su postgres -c 'cd /opt/local/var/db/postgresql15 && /opt/local/lib/postgresql15/bin/initdb -D /opt/local/var/db/postgresql15/defaultdb
sudo port load postgresql15-server(Your life will be much easier if you use macports. Don't use brew for installing PG.)
In order for sudo -u postgres psql to work without error messages, you should chmod 755 ~.
Ubuntu 18.04+
Install OS packages:
textapt update apt install build-essential python3 python3-pip virtualenvwrapper postgresql postgresql-contrib wget screenYou may also need to increase your max watched file limit (see issue):
textecho fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
asdf
asdf (https://asdf-vm.com/) manages multiple versions of runtimes/tools that we use, such as node and python.
This can be useful if you need to work in multiple environments on the same machine.
Versions are kept in version control in .tool-versions and .envrc.
- Install
asdf: https://asdf-vm.com/guide/getting-started.html - Install plugins:text
asdf plugin add nodejs asdf plugin add python asdf plugin add direnv - Run
asdf installfrom the root directory (and any dir with.tool-versions). - In the root directory, run:
direnv allow. - Check that the installed tools work and have the correct version.bash
node --version python --version
Notes:
- You want asdf for python instead of using your Mac's system python because
- in the latest MacOS 12.6 (which suddenly switches to python 3.9) building binary packages within certain environments like the pre-commit pyenv is broken, unless maybe you install Xcode.
- we have more consistent control across platforms of which python we are relying on, which can have subtle effects on the chances of success of npm gyp builds. Plus, no more sudden switching python 3.8 to 3.9 (for ex) just because you updated MacOS!
- You want asdf-direnv so that:
- you get local virtualenv's managed by direnv (what's called "layouts" in direnv) - these local envs are not handled by asdf.
- things like
node --various-node-flags $(which pnpm)work as expected (used in various scripts). - plus the general benefits of avoiding shims.
Docker setup
By default, the source code is mounted as a shared volume with the host. The node modules are mounted separately, each having their own volume, in order to cache dependency installation and make sure we don't pollute the shared volume with the built artifacts.
This setup is quite heavy on CPU/RAM consumption, make sure you have at least 8GB of RAM available for the application container.
Launching the app through docker takes just a single command from the root of the repository:
docker-compose up -dIt will automatically spin up database, seed it, perform all the migrations, build all the source code needed for the studio to operate properly, and launch the server.
Manual setup (suggested)
Before proceeding, make sure you have configured your database and git hooks.
1. Environment variables
Make sure the root of your project and ./platform/wab folder contain the following .env files:
DATABASE_URI=postgres://wab:SEKRET@localhost:5432/wab
WAB_DBNAME=plasmic-db
WAB_DBPASSWORD=SEKRET
NODE_ENV=development2. Installing dependencies
Run pnpm install in the root folder, then pnpm install in ./platform (one pnpm workspace covering wab, canvas-packages, loader-bundle-env and loader-html-hydrate)
Configuring Git and Git hooks
The root pnpm install also sets up the repository's Git hooks through Husky. In a fresh Git worktree, run it at the worktree root before your first commit. The generated, gitignored .husky/_ directory is absent until the install runs, so Git silently skips the hooks.
3. Seeding the database
In the ./platform/wab run:
pnpm seed4. Application setup
In the project root directory, run:
pnpm setup-all && pnpm bootstrap5. Starting dev servers
Run all servers (frontend, backend, and watchers):
pnpm devUsing the app
The app runs on http://localhost:3003/.
If you have freshly reset the DB, the following users will be created for you
(see seed script for details):
The password for these accounts is !53kr3tz!.
WARNING: Avoid testing with the [email protected] user.
By default, the admin.example.com domain is considered an admin and has
elevated privileges (e.g. access to all teams, workspaces, projects, etc).
For most development purposes, use a normal user such as [email protected].
Troubleshooting
Executable `hadolint` not found
Install hadolint if you do any changes to the docker configs
tools/dev.bash: line 3: concurrently: command not found
If your /platform/wab/tools/dev.bash throws an error about concurrently not being a function, re-write it as npx concurrently
Next steps
Dive deeper into the tooling and configuration in 01-config-tooling.md.
Contributing Corporate Cla (`docs/contributing/corporate-cla.md`)
In order to clarify the intellectual property license granted with Contributions from any person or entity, Plasmic Inc ("Plasmic") must have a Contributor License Agreement (CLA) on file that has been signed by each Contributor, indicating agreement to the license terms below. This license is for your protection as a Contributor as well as the protection of Plasmic and its users; it does not change your rights to use your own Contributions for any other purpose.
This version of the Agreement allows an entity (the "Corporation") to submit Contributions to Plasmic, to authorize Contributions submitted by its designated employees to Plasmic, and to grant copyright and patent licenses thereto.
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to Plasmic. Except for the license granted herein to Plasmic and recipients of software distributed by Plasmic, You reserve all right, title, and interest in and to Your Contributions.
Definitions.
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with Plasmic. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean the code, documentation or any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Plasmic for inclusion in, or documentation of, any of the products owned or managed by Plasmic (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Plasmic or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Plasmic for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Plasmic and to recipients of software distributed by Plasmic a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Plasmic and to recipients of software distributed by Plasmic a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation designated by You is authorized to submit Contributions on behalf of the Corporation.
You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others).
You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
Should You wish to submit work that is not Your original creation, You may submit it to Plasmic separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
It is your responsibility to notify Plasmic when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with Plasmic.
Contributing Individual Cla (`docs/contributing/individual-cla.md`)
In order to clarify the intellectual property license granted with Contributions from any person or entity, Plasmic Inc ("Plasmic") must have a Contributor License Agreement ("CLA") on file that has been signed by each Contributor, indicating agreement to the license terms below. This license is for your protection as a Contributor as well as the protection of Plasmic; it does not change your rights to use your own Contributions for any other purpose.
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to Plasmic. Except for the license granted herein to Plasmic and recipients of software distributed by Plasmic, You reserve all right, title, and interest in and to Your Contributions.
Definitions.
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with Plasmic. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Plasmic for inclusion in, or documentation of, any of the products owned or managed by Plasmic (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Plasmic or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Plasmic for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Plasmic and to recipients of software distributed by Plasmic a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Plasmic and to recipients of software distributed by Plasmic a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to Plasmic, or that your employer has executed a separate Corporate CLA with Plasmic.
You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.
You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
Should You wish to submit work that is not Your original creation, You may submit it to Plasmic separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
You agree to notify Plasmic of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
Contributing Platform 01 Config Tooling (`docs/contributing/platform/01-config-tooling.md`)
Developing Plasmic Studio: config and tooling guide
Config (optional)
Write something like this in ~/.plasmic/secrets.json:
{
"encryptionKey": "dummykey",
"google": {
"clientId": "SEE_GOOGLE_INSTRUCTIONS_BELOW",
"clientSecret": "SEE_GOOGLE_INSTRUCTIONS_BELOW"
},
"resendApiKey": "SET_THIS_TO_RESEND_API_KEY",
"smtpAuth": {
"user": "SET_THIS_TO_SMTP_USER",
"pass": "SET_THIS_TO_SMTP_KEY"
},
"segmentWriteKey": "ignorethis"
}You'll also need ~/.aws/credentials, since various parts such as codegen/publish and Figma import use S3.
Database
Setup DB
On project root directory, make sure the Postgresql server is running, and run:
pnpm db:setup
pnpm db:reset # specify no_sudo=1 if `sudo -u postgres psql` doesn't workReset DB State
If you ever want to, you can reset the DB state by running (on project root):
pnpm db:reset # specify no_sudo=1 if `sudo -u postgres psql` doesn't workImportant: remember clearing your browser cookies and restart any running servers.
Running Servers
Running Servers using screen
From platform/wab, run all servers in screens:
bash tools/start.bashIf you'd like to disable type-checking for faster incremental dev-server builds,
use:
NO_TYPECHECK=1 bash tools/start.bashAfter start.bash, you'll automatically get three panes viewing various terminals, each one running some subset of procseses.
(Experimental) Running on different ports
If you'd like to run on an alternate backend (app server) port:
BACKEND_PORT=3007 bash tools/start.bashIf you'd like to run on an alternate frontend (webpack dev server) port:
PORT=3006 bash tools/start.bashIf you'd like to run on an alternate database name:
WAB_DBNAME=altwab bash tools/start.bash(Incomplete) Running Servers manually
(This just documents running things in wab, but you must also run things outside of wab.)
In wab folder
Run backend
pnpm backendRun frontend client dev server
pnpm startRun host client, just a proxy on port 3005 to the frontend
pnpm host-serverRunning Servers using pm2
You can also use pm2 to manage all the server processes in dev environment.
First, initialize the shell as:
workon wab
. ~/.node/*/bin/activateInstall pm2 globally so you can use pm2 rather than "pnpm pm2"
npm install pm2To start all processes, just
cd wab
pm2 start pm2-dev.config.jsTo stop all processes,
pm2 stop allTo delete all processes,
pm2 delete allTo inspect logs,
pm2 logsRefer to https://pm2.keymetrics.io/docs/usage/quick-start/ for more usage information.
When pulling codebase
Whenever you fetch the latest changes, most of the time, you just need to run:
pnpm install
make
# restart node server
# restart webpack, once in a blue moonBut if something is still going wrong, try:
pnpm setup
# restart node server
# restart webpack, once in a blue moonIf the above doesn't fix the issue, try again but running pnpm setup-all instead.
SVG Icons
For the in-flux SVG icons, install the icon fonts from https://github.com/keremciu/font-bundles
Plume special package
To make sure your local database contains the latest version of the Plume
package so that you can create components from Plume templates, run:
pnpm plume:dev updateIf you don't do so, studio may show a NotFoundError when you open any new
project.
Testing
Run unit tests with:
bash tools/test.bashMigrating DB/model bundle schema
To migrate bundles, create a new file in the bundle-migrations following the same format as existing files. Small example:
// wab/src/wab/server/bundle-migrations/XX-my-migration.ts
import { UnsafeBundle } from "../../shared/bundles";
export function migrate(bundle: UnsafeBundle) {
for (const [k, v] of Object.entries(bundle.map)) {
if (v.__type === "Rule") {
v.values = v.values;
}
}
}And that is!
If you want to revert, simply remove the file and then restart the app server. WARNING: this will occur in data loss. If you can create a new migration instead, do so!
In reality, you only have to worry about adding files and reverting files. Our deployment scripts will take care of the rest. Here's a brief explanation on how to do the changes in your local environment:
- Migrating: add a new migration and restart the server.
- Reverting: remove the migration and restart the server.
Migrating dev/test bundles
We have some local JSON bundles for development/test purposes, which you also need to migrate.
To migrate these, run:
pnpm migrate-dev-bundlesThis runs any necessary migrations according to the version stamp.
Then make sure you run the tests and update the snapshots.
NOTE: This will first do a git checkout on the file, resetting to a fresh checkout state! This lets you repeatedly test and run your migration script on the file.
Debugging Studio
Because Studio runs in a cross-origin iframe, debugging becomes a bit trickier.
In particular, the React Devtools Chrome extension will not work. However, you can run the standalone React Devtools Electron package.
Install and run react-devtools:
npm install react-devtools
react-devtoolsAlternatively you can run it with npx:
npx react-devtoolsAnd now when you open up Studio with the devflag ?enableReactDevTools=true and it should auto-connect.
It should work for both dev server and prod.
Debugging Node Server
You can use IntelliJ/Webstorm.
Or use node --inspect to debug your node app using Chrome DevTools - just open about:inspect in Chrome as per
https://medium.com/@paul_irish/debugging-node-js-nightlies-with-chrome-devtools-7c4a1b95ae27.
Ant
We're opting to import all Ant styles wholesale and override their globals
in antd-overrides.less. This allows for live theming (no dev server restarts
necessary).
Maintaining dependencies
Check what dependencies are not used (or missing):
pnpm knip:depsCheck what needs to be updated:
pnpm outdatedUpdate the dependencies:
pnpm up --latestThis will upgrade everything. You can also try selectively upgrading individual
packages, but things get complicated with upgrading dependencies that are
also indirect dependencies of other dependencies.
Alternate configs
When pointing to a different DB, you currently have to make sure you locally
edit ormconfig.json (used by typeorm CLI) and set the WAB_DBNAME env var.
Audit licenses of dependencies
For node dependencies, do this from each project directory:
npx license-checker --csv --out license-checker.csvFor Python dependencies, do this from each project directory:
pip-licenses --from=mixed -f csv > pip-licenses.csvProduction Build
Run pnpm build to build client app for production. This takes a long time (>5m).
You can test out your built artifact with:
npm install local-web-server
cd build/
ws --spa index.html --rewrite '/api/(.*) -> http://localhost:3004/api/$1'Then open http://localhost:8000.
Contributing Platform 02 Integrations (`docs/contributing/platform/02-integrations.md`)
Developing Plasmic Studio: third-party system integrations
Figma import
See Figma plugin setup.
Plasmic hosting on Vercel
To locally access a Plasmic-hosted project, run the hosting application fromplatform/hosting:
cd platform/hosting
pnpm devTo run it against a local Studio project, temporarily hardcode the local project'sprojectId, token, and wantToShowBadge inplatform/hosting/pages/_sites/[site]/[[...catchall]].tsx. Then set the API host:
cd platform/hosting
NEXT_PUBLIC_PLASMIC_HOST=http://localhost:3003 pnpm devYou can access a published project at http://localhost:3000/_sites/yourdomain.plasmic.run,
which is equivalent to yourdomain.plasmic.run.
Setting up Google SSO
For now, users who use SSO must have an email domain that matches an org's domain.
Each developer who works on Plasmic and wants to try out SSO will need to set up
a project on Google Developers Console.
- Go to Google Developers Console
- On the upper-left corner, you can see the Project you are using (next to three black hexagons).
Click it, and in the dialog box, click "New Project" on the upper-right. - Name your project something like "Plasmic Yang Dev"
- Click on the Credentials tab on the left sidebar.
- First click on the "OAuth consent screen". Fill in the required fields, and for scopes,
make sure "email", "profile", "openid" are included (should be by default). - Next, click on the "Credentials tab"
- Select "Create credentials", and choose "OAuth Client ID".
- Application type: "Web application"
- Name:
- Authorized Javascript origins: [http://localhost:3003]
- Authorized redirect URIs: [http://localhost:3003/api/v1/oauth2/google/callback]
- Save the client ID and secret in your
~/.plasmic/secrets.json. It should look like:json{ "encryptionKey": "this is a secret DB encryption key", "google": { "clientId": "YOUR CLIENT ID", "clientSecret": "YOUR CLIENT SECRET" } }
Setting up GitHub App
Sign in to GitHub with your personal account and go to
GitHub Developer Settings.Create a new GitHub App with the following information:
- Homepage URL: http://localhost:3003
- Callback URL: http://localhost:3003/github/callback
- Uncheck "Expire user authorization tokens"
- Check "Request user authorization (OAuth) during installation"
- Deactivate webhook
- Repository permissions:
- Actions: Read & write
- Administration: Read & write
- Contents: Read & write
- Pages: Read & write
- Pull requests: Read & write
- Workflows: Read & write
Click on "Edit" in the app you created and generate/store a client secret
and a private key.Fill the following fields in your ~/.plasmic/secrets.json:
json{ "github": { "appId": "<APP_ID>", "privateKey": "-----BEGIN RSA PRIVATE KEY-----\n<YOUR_KEY>...", "oauth": { "clientId": "<CLIENT_ID>", "clientSecret": "<CLIENT_SECRET>" } } }Note that the private key must have its line breaks replaced by "\n".
Edit the devflags (in your local storage) changing githubClientId and
githubAppName to your app client ID and kebab-cased name (copy it from the
app URL), then reload studio for changes to take effect.
Developing/debugging GitHub integration
Here are various tips and tools for localhost development.
Set an externally facing URL
GitHub Actions needs to call your app server to perform syncs, so use a service
like localhost.run and set your externalBaseUrl devflag to point to your
resulting temp URL.
Use toolchain debug flags
We internally use our own toolchain including create-plasmic-app,
@plasmicapp/cli, @plasmicapp/loader, etc. For local-only testing in a pnpm
project, use the local-link setup/build/teardown workflow documented in
CONTRIBUTING.md. It uses temporary file: overrides
without changing the package versions declared by the consuming project. You
can also use the various debug flags for those packages likePLASMIC_DEFAULT_HOST.
For example, to have the CLI/PlasmicLoader point to your own localhost server:
PLASMIC_DEFAULT_HOST=http://localhost:3003 pnpm backendThis is ignored by the app server but consumed by CLI/PlasmicLoader.
See the various READMEs on those projects for relevant debug flags.
Publish the toolchain first
The CLI/PlasmicLoader does eventually get run on GitHub Actions runners, so the "easiest" way to test things for now is to publish first.
Potentially, you can also amend the resulting package.json (in the repo that gets pushed to GitHub) to point to some alternate package source, but I haven't done/needed this yet.
Setting up billing (Stripe)
To test billing locally, add Stripe test secret key (https://dashboard.stripe.com/test/apikeys) to secrets.json:
{
"stripe": {
"secretKey": "<PASTE_SECRET_KEY_HERE>"
}
}Setting up Google Sheets
Have a GCloud account, Sheets API enabled, OAuth consent screen.
Create an OAuth client.
- Type: web application
- Redirects: http://localhost:3003/api/v1/oauth2/google-sheets/callback
Save into secrets.json:
{
"google-sheets": {
"clientId": "<CLIENT_ID>",
"clientSecret": "<CLIENT_SECRET>"
}
}Contributing Platform 03 Figma (`docs/contributing/platform/03-figma.md`)
Figma plugin setup
The plugin copies a clipId and uploads selected layers through a web bridge (figma-plugin-web) to PUT /api/v1/clip/:clipId. Studio fetches the data on paste with GET /api/v1/clip/:clipId.
Use the production plugin
For internal development, use the published plugin if your Studio app server has authorized read access to production clip storage. Set CLIP_BUCKET, S3_ENDPOINT, and AWS credentials to match that storage, then restart the server. Having ~/.aws/credentials alone does not grant access.
For separate storage, configure the bridge and exporter below.
Configure storage
Set these on the Studio app server:
CLIP_BUCKET=your-figma-clips
# For S3-compatible storage:
# S3_ENDPOINT=https://s3.example.comUse a private bucket and AWS credentials with GetObject and PutObject access. Allow multipart operations for large uploads. No public
bucket access or bucket CORS is needed. CLIP_BUCKET defaults to plasmic-clips, S3_ENDPOINT also affects other app server storage clients. The clip client doesn't force path-style addressing.
Clip routes don't need Studio auth or CSRF, anyone with a clip ID can retrieve it. Remember to set an expiration policy.
Serve the web bridge
Use the repositoryโs Node version and each packageโs pinned pnpm version.
From the repository root:
cd platform/figma-plugin-web
pnpm install --frozen-lockfile
PUBLIC_URL=/figma-plugin-app NODE_OPTIONS=--openssl-legacy-provider SKIP_PREFLIGHT_CHECK=true pnpm buildThe flags are for Webpack 4 on Node 24 and Create React Appโs ancestor dependency check. Serve build/ at https://studio.example.com/figma-plugin-app/, on the same origin as the Studio API. The bridge uses relative /api/v1/... URLs.
Build the exporter
In platform/figma-plugin-plasmic-exporter:
Set iframe
srcinsrc/ui/components/App.tsxto your URL, e.g.https://studio.example.com/figma-plugin-app/.Set
networkAccess.allowedDomainsinmanifest.jsonto["https://studio.example.com"]. For local development, usedevAllowedDomainswith HTTPS origin and port (Figma manifest reference).Build:
shpnpm install --frozen-lockfile NODE_OPTIONS=--openssl-legacy-provider pnpm build
In Figma desktop, choose Plugins โ Development โ Import plugin from manifestโฆ and select this packageโs manifest.json. Run that plugin, select layers, click Export selected layers to clipboard, wait for completion, and paste into Studio. Rebuild and relaunch after source changes, and distribute manifest.jsonand dist/ together.
Troubleshoot
- Export hangs: check bridge assets, HTTPS, iframe URL, manifest allowlist, framing headers, and login redirects in Figmaโs developer console.
- Upload fails: check the PUT response and app logs for storage permissions, routing, or request size limits.
- Paste cannot find the clip: verify the pluginโs destination and Studioโs bucket/endpoint match. The published plugin uses production storage.
Sources: bridge,
clip API,
paste handler.
Contributing Platform Dev Notes (`docs/contributing/platform/dev-notes.txt`)
React Gotchas
- For some reason, if a component crashes on the first render (within the
ViewInitializer's firstsetState({viewCtx})), this causes some very
confusing issues with attempting to reload the base-pkg and refresh the app
again from the top. This might manifest as an attempt to render
foreign components and then not finding the component in
ForeignComponents.forValComponent(). I ran into this when e.g. enabling
CreateTab rendering earlier (renders the gallery even when no selection is
active, but there was a silly bug in CreateItem triggering the above symptoms)
Library Gotchas
- Do not import from "jquery", always use the one from deps. They have
different plugins, but more subtlely, they have different .data() stores.
WAB Gotchas
Tpls.ancestors doesn't do any filtering, but canvasCtx().valAncestors() filters
out the valUserRoot! (Which is good since in both isolated component editing
mode and normal page editing mode, they're more like sentinels.)Tagger will actually tag the portaled div of a React Bootstrap Modal on first
render (as seen in componentDidMount), but not later updates that re-show the
div (componentDidUpdate just sees null). I'm not able to repro that initial
tagging outside of WAB---see e.g. https://codesandbox.io/s/q8828q9p69. So
don't rely on that initial tagging.Currently, when you insert a Modal, you might have this val tree:
ValComponent for Modal
ValComponent for ModalBody
ValTag for divwhich renders as these React components:
CanvasElement
Sub
Modal
ModalBody <-- Modal expects ModalBody to be its direct child
Sup
CanvasElement
divBecause of that parent-child requirement, we unfortunately can't interleave a
CanvasElement, which would let us more easily associate the DOM node (with
.getDOMNode() or .findDOMNode()) with that ValComponent (without overriding
more bsRole settings---which may be a good thing to consider eventually).
Platform Wab Docs ICONS (`platform/wab/docs/ICONS.md`)
Icons
Studio icons are SVG React components generated by Plasmic, not hand-written
files. Most of them come from the [PlasmicKit] Icons project
(oT38tGyqov9SPWHpf3Y2Rf) and land insrc/wab/client/plasmic/plasmic_kit_icons/icons/PlasmicIcon__*.tsx. A few
older ones live under the other src/wab/client/plasmic/plasmic_kit_*/
directories.
Adding a new icon
Check whether an existing icon works first. There are ~600 of them, so
searchsrc/wab/client/plasmic/plasmic_kit_icons/icons/before drawing
anything new.Add the SVG as an icon asset in the
[PlasmicKit] IconsPlasmic project,
following the conventions below.Sync it into the repo:
textpnpm plasmic:syncThis writes the generated component and registers it in
plasmic.json.
Commit both.Give it a semantic name in
src/wab/client/icons.tsxrather than importing
the generatedPlasmicIcon__*module all over the codebase.
SVG conventions
New icons should match the existing set:
viewBox="0 0 24 24"(the set is drawn at 24ร24, even though it renders at
16px by default)fill="none"on the<svg>element; draw with strokes, not fillsstroke="currentColor"so the icon inherits text color โ never hardcode a
colorstroke-width="1.5"stroke-linecap="round"andstroke-linejoin="round"- Prefer a single `` over many primitives
- Keep the artwork inside the 24ร24 box with a consistent margin instead of
bleeding to the edges, so icons look the same weight when placed side by side
An existing icon that follows all of the above, useful as a reference:src/wab/client/plasmic/plasmic_kit_icons/icons/PlasmicIcon__Braces.tsx.
Using an icon
Render icons through the Icon widget, which applies the standard sizing
(16px) and the custom-svg-icon class:
import { Icon } from "@/wab/client/components/widgets/Icon";
import BracesIcon from "@/wab/client/plasmic/plasmic_kit_icons/icons/PlasmicIcon__Braces";
<Icon icon={BracesIcon} />;Pass size to override the default, and monochromeExempt for the rare icon
that should keep its own colors.
--- METRICS ---
- Files Extracted: 9
- Estimated Token Budget: ~12548 tokens
- Canonical Reference: https://codewiki.google/github.com/plasmicapp/plasmic