38
loading...
This website collects cookies to deliver better user experience
node
and a package manager like npm
or yarn
.mkdir <your-plugin-name>
cd <your-plugin-name>
# If using yarn
yarn init
#If using npm
npm init
code .
# yarn
yarn add -D rollup sirv-cli @rollup/plugin-node-resolve @rollup/plugin-commonjs rollup-plugin-livereload rollup-plugin-terser svelte-preprocess rollup-plugin-postcss rollup-plugin-html-bundle
# NPM
npm install --save-dev rollup sirv-cli @rollup/plugin-node-resolve @rollup/plugin-commonjs rollup-plugin-livereload rollup-plugin-terser svelte-preprocess rollup-plugin-postcss rollup-plugin-html-bundle
code.js
template.html
main.js
src
folder and add it code.js
, template.html
and main.js
.rollup.config.js
at your project's root and this should be the content:import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import livereload from 'rollup-plugin-livereload'
// Minifier
import { terser } from 'rollup-plugin-terser'
// Post CSS
import postcss from 'rollup-plugin-postcss'
// Inline to single html
import htmlBundle from 'rollup-plugin-html-bundle'
const production = !process.env.ROLLUP_WATCH
export default [
// MAIN.JS
// The main JS for the UI, will built and then injected
// into the template as inline JS for compatibility reasons
{
input: 'src/main.js',
output: {
format: 'umd',
name: 'ui',
file: 'public/bundle.js',
},
plugins: [
// Handle external dependencies and prepare
// the terrain for svelte later on
resolve({
browser: true,
dedupe: (importee) =>
importee === 'svelte' || importee.startsWith('svelte/'),
extensions: ['.svelte', '.mjs', '.js', '.json', '.node', '.ts'],
}),
commonjs({ transformMixedEsModules: true }),
// Post CSS config
postcss({
extensions: ['.css'],
}),
// This inject the bundled version of main.js
// into the the template
htmlBundle({
template: 'src/template.html',
target: 'public/index.html',
inline: true,
}),
// If dev mode, serve and livereload
!production && serve(),
!production && livereload('public'),
// If prod mode, we minify
production && terser(),
],
watch: {
clearScreen: true,
},
},
// CODE.JS
// The part that communicate with Figma directly
// Communicate with main.js via event send/binding
{
input: 'src/code.js',
output: {
file: 'public/code.js',
format: 'iife',
name: 'code',
},
plugins: [
resolve(),
commonjs({ transformMixedEsModules: true }),
production && terser(),
],
},
]
function serve() {
let started = false
return {
writeBundle() {
if (!started) {
started = true
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true,
})
}
},
}
}
package.json
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public"
},
console.log
to main.js
and run yarn dev
or npm run dev
. It should serve the static built files over http://localhost:5000.manifest.json
at the root with the following content:{
"name": "<your-plugin-name>",
"id": "<fill-that-before-publish>",
"api": "1.0.0",
"main": "public/code.js",
"ui": "public/index.html"
}
Right click → Plugins → Development → New Plugin...
and the popup will ask you to chose a manifest file.manifest.json
and you can now launch your plugin in Figma by doing Right click → Plugins → Development → <your-plugin-name>
.src/code.js
:figma.showUI(__html__, { width: 800, height: 600 })
template.html
..svelte
files.yarn add -D svelte svelte-preprocess rollup-plugin-svelte
rollup.config.js
file:// Svelte related
import svelte from 'rollup-plugin-svelte'
import autoPreprocess from 'svelte-preprocess'
plugin
array around line 32 and paste it that code:// Svelte plugin
svelte({
// enable run-time checks when not in production
dev: !production,
preprocess: autoPreprocess(),
onwarn: (warning, handler) => {
const { code, frame } = warning
if (code === "css-unused-selector" && frame.includes("shape")) return
handler(warning)
},
}),
rollup.config.js
should look like this:import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import livereload from 'rollup-plugin-livereload'
// Svelte related
import svelte from 'rollup-plugin-svelte'
import autoPreprocess from 'svelte-preprocess'
// Minifier
import { terser } from 'rollup-plugin-terser'
// Post CSS
import postcss from 'rollup-plugin-postcss'
// Inline to single html
import htmlBundle from 'rollup-plugin-html-bundle'
const production = !process.env.ROLLUP_WATCH
export default [
// MAIN.JS
// The main JS for the UI, will built and then injected
// into the template as inline JS for compatibility reasons
{
input: 'src/main.js',
output: {
format: 'umd',
name: 'ui',
file: 'public/bundle.js',
},
plugins: [
// Svelte plugin
svelte({
// enable run-time checks when not in production
dev: !production,
preprocess: autoPreprocess(),
onwarn: (warning, handler) => {
const { code, frame } = warning
if (code === 'css-unused-selector' && frame.includes('shape')) return
handler(warning)
},
}),
// Handle external dependencies and prepare
// the terrain for svelte later on
resolve({
browser: true,
dedupe: (importee) =>
importee === 'svelte' || importee.startsWith('svelte/'),
extensions: ['.svelte', '.mjs', '.js', '.json', '.node', '.ts'],
}),
commonjs({ transformMixedEsModules: true }),
// Post CSS config
postcss({
extensions: ['.css'],
}),
// This inject the bundled version of main.js
// into the the template
htmlBundle({
template: 'src/template.html',
target: 'public/index.html',
inline: true,
}),
// If dev mode, serve and livereload
!production && serve(),
!production && livereload('public'),
// If prod mode, we minify
production && terser(),
],
watch: {
clearScreen: true,
},
},
// CODE.JS
// The part that communicate with Figma directly
// Communicate with main.js via event send/binding
{
input: 'src/code.js',
output: {
file: 'public/code.js',
format: 'iife',
name: 'code',
},
plugins: [
resolve(),
commonjs({ transformMixedEsModules: true }),
production && terser(),
],
},
]
function serve() {
let started = false
return {
writeBundle() {
if (!started) {
started = true
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true,
})
}
},
}
}
src/Main.svelte
and populate it with:<script>
let value = "change me!"
</script>
<input type="text" bind:value>
{value}
main.js
:import App from './Main'
const app = new App({
target: document.body,
})
export default app
code.js
first, code.js
can then use the Figma API.Main.svelte
:<script>
const handleClick = () => {
parent.postMessage(
{
pluginMessage: {
type: "createShape",
},
},
"*"
)
}
</script>
<button on:click={handleClick}>Create a Shape</button>
createShape
message with parent.postMessage
when the button is clicked.code.js
:figma.showUI(__html__, { width: 800, height: 600 })
figma.ui.onmessage = (msg) => {
if (msg.type === 'createShape') {
// Create a rectangle
let rectangle = figma.createRectangle()
// Making it 400x400
rectangle.resize(400, 400)
// Making it Blue
rectangle.fills = [{ type: 'SOLID', color: { r: 0, g: 0, b: 1 } }]
// Focus on it
figma.viewport.scrollAndZoomIntoView([rectangle])
// Close the plugin
figma.closePlugin()
}
}
createShape
event.scss
files support. Also we'll allow to specify a lang="scss"
in our style
tags.# Yarn
yarn add -D node-sass
# NPM
npm install --save-dev node-sass
<style lang="scss">
in your svelte files and import your global stylesheet with @import 'main.scss';
.import './main.scss';
too.figma
object. You'll also be able to use TS in your svelte file using <script lang="ts">
!# Yarn
yarn add -D typescript tslib rollup-plugin-typescript
# NPM
npm install --save-dev typescript tslib rollup-plugin-typescript
tsconfig.json
file:{
"compilerOptions": {
"baseUrl": ".",
"target": "esnext",
"moduleResolution": "node",
"esModuleInterop": true
},
"include": ["./src"]
}
rollup.config.js
:import typescript from 'rollup-plugin-typescript'
main.js
compilation we'll add typescript({ sourceMap: !production }),
after the commonjs
plugin (around line 56
).code.js
compilation too (line 97
).import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import livereload from 'rollup-plugin-livereload'
// Svelte related
import svelte from 'rollup-plugin-svelte'
import autoPreprocess from 'svelte-preprocess'
// Minifier
import { terser } from 'rollup-plugin-terser'
// Post CSS
import postcss from 'rollup-plugin-postcss'
// Inline to single html
import htmlBundle from 'rollup-plugin-html-bundle'
// Typescript
import typescript from 'rollup-plugin-typescript'
const production = !process.env.ROLLUP_WATCH
export default [
// MAIN.JS
// The main JS for the UI, will built and then injected
// into the template as inline JS for compatibility reasons
{
input: 'src/main.js',
output: {
format: 'umd',
name: 'ui',
file: 'public/bundle.js',
},
plugins: [
// Svelte plugin
svelte({
// enable run-time checks when not in production
dev: !production,
preprocess: autoPreprocess(),
onwarn: (warning, handler) => {
const { code, frame } = warning
if (code === 'css-unused-selector' && frame.includes('shape')) return
handler(warning)
},
}),
// Handle external dependencies and prepare
// the terrain for svelte later on
resolve({
browser: true,
dedupe: (importee) =>
importee === 'svelte' || importee.startsWith('svelte/'),
extensions: ['.svelte', '.mjs', '.js', '.json', '.node', '.ts'],
}),
commonjs({ transformMixedEsModules: true }),
// Typescript
typescript({ sourceMap: !production }),
// Post CSS config
postcss({
extensions: ['.css'],
}),
// This inject the bundled version of main.js
// into the the template
htmlBundle({
template: 'src/template.html',
target: 'public/index.html',
inline: true,
}),
// If dev mode, serve and livereload
!production && serve(),
!production && livereload('public'),
// If prod mode, we minify
production && terser(),
],
watch: {
clearScreen: true,
},
},
// CODE.JS
// The part that communicate with Figma directly
// Communicate with main.js via event send/binding
{
input: 'src/code.js',
output: {
file: 'public/code.ts',
format: 'iife',
name: 'code',
},
plugins: [
typescript(),
resolve(),
commonjs({ transformMixedEsModules: true }),
production && terser(),
],
},
]
function serve() {
let started = false
return {
writeBundle() {
if (!started) {
started = true
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true,
})
}
},
}
}
<script lang="ts">
in our svelte components 🤩🤩🤩figma
object and convert code.js
to code.ts
.# Yarn
yarn add -D @figma/plugin-typings
# NPM
npm install --save-dev @figma/plugin-typings
tsconfig.json
file:{
"compilerOptions": {
...
"typeRoots": [
"./node_modules/@types",
"./node_modules/@figma"
]
}
}
code.js
into code.ts
. We'll need to replace the reference to it on rollup.config.js
line 90
input: "src/code.ts",