はじめに
Figmaのプラグインを作成する環境をWebpackを使って構築する方法は、下記の公式ドキュメントで案内されてます。
Bundling with Webpack · Figma Developers
ただ、上記のドキュメントの通りにやってみたところエラーが出てしまい一部手を加えたので、備忘録的に記事に残しておきます。
1. デスクトップアプリから新しいプラグイン作成
Figmaデスクトップアプリのメニュー、plugins > Development > New plugin から新規プラグイン作成。
今回は「Figma design」の「With UI browser APIs」を選択。
2. パッケージのインストール
pluginのディレクトリに移動し、使用するパッケージをインストール。
npm install --save-dev css-loader html-inline-script-webpack-plugin html-webpack-plugin style-loader ts-loader typescript url-loader webpack webpack-cli
ドキュメントでは、html-webpack-inline-source-plugin
を使用してるのですが、これがエラーで動かなかったので代わりに html-inline-script-webpack-plugin
を使用してます。
@figma/plugin-typings
もインストール。
npm install --save-dev @figma/plugin-typings
3. プロジェクト用にファイルを設置
src
ディレクトリを作成し、下記のファイルを設置。
src/ui.html
<img src="<%= require('./logo.svg') %>">
<h2>Rectangle Creator</h2>
<p>Count: <input id="count" value="5"></p>
<button id="create">Create</button>
<button id="cancel">Cancel</button>
src/logo.svg
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27 5V27H5M31 9V31H9M1 1H23V23H1V1Z" stroke="black" stroke-width="2"/>
</svg>
src/ui.ts
import './ui.css'
window.addEventListener('load', () => {
document.getElementById('create').onclick = () => {
const textbox = document.getElementById('count') as HTMLInputElement
const count = parseInt(textbox.value, 10)
parent.postMessage({ pluginMessage: { type: 'create-rectangles', count } }, '*')
}
document.getElementById('cancel').onclick = () => {
parent.postMessage({ pluginMessage: { type: 'cancel' } }, '*')
}
})
src/ui.css
body {
font: 12px sans-serif;
text-align: center;
margin: 20px;
}
button {
border-radius: 5px;
background: white;
color: black;
border: none;
padding: 8px 15px;
margin: 0 5px;
box-shadow: inset 0 0 0 1px black;
outline: none;
}
#create {
box-shadow: none;
background: #18A0FB;
color: white;
}
input {
border: none;
outline: none;
padding: 8px;
}
input:hover { box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); }
button:focus { box-shadow: inset 0 0 0 2px #18A0FB; }
#create:focus { box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.3); }
input:focus { box-shadow: inset 0 0 0 2px #18A0FB; }
src/code.ts
figma.showUI(__html__)
figma.ui.onmessage = msg => {
if (msg.type === 'create-rectangles') {
const nodes = []
for (let i = 0; i < msg.count; i++) {
const rect = figma.createRectangle()
rect.x = i * 150
rect.fills = [{type: 'SOLID', color: {r: 1, g: 0.5, b: 0}}]
figma.currentPage.appendChild(rect)
nodes.push(rect)
}
figma.currentPage.selection = nodes
figma.viewport.scrollAndZoomIntoView(nodes)
}
figma.closePlugin()
}
4. manifest.jsでバンドルされたファイルをポイント
バンドルされたコードを dist
ディレクトリに出力するようにWebpackをセットアップするので、これらのバンドルファイルを指すように manifest.json
を変更する。
{
...
"main": "dist/code.js",
"ui": "dist/ui.html",
...
}
5. webpackの設定
webpack.config.js
を作成し、下記のように設定をする。
const HtmlInlineScriptWebpackPlugin = require('html-webpack-inline-source-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = (env, argv) => ({
mode: argv.mode === 'production' ? 'production' : 'development',
// This is necessary because Figma's 'eval' works differently than normal eval
devtool: argv.mode === 'production' ? false : 'inline-source-map',
entry: {
ui: './src/ui.ts', // The entry point for your UI code
code: './src/code.ts', // The entry point for your plugin code
},
module: {
rules: [
// Converts TypeScript code to JavaScript
{ test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/ },
// Enables including CSS by doing "import './file.css'" in your TypeScript code
{ test: /\.css$/, use: ['style-loader', { loader: 'css-loader' }] },
// Allows you to use "<%= require('./file.svg') %>" in your HTML code to get a data URI
{ test: /\.(png|jpg|gif|webp|svg)$/, use: [{ loader: 'url-loader', options: { esModule: false }}] },
],
},
// Webpack tries these extensions for you if you omit the extension like "import './file'"
resolve: { extensions: ['.tsx', '.ts', '.jsx', '.js'] },
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'), // Compile into a folder called "dist"
},
// Tells Webpack to generate "ui.html" and to inline "ui.ts" into it
plugins: [
new HtmlWebpackPlugin({
template: './src/ui.html',
filename: 'ui.html',
inlineSource: '.(js)$',
chunks: ['ui'],
}),
new HtmlInlineScriptWebpackPlugin([
/ui.js$/
]),
],
})
6. ts.configの設定
.ts.config
の lib
に dom
を追加
"lib": ["es6", "dom"],
7. 完了
以上で完了。
開発時は、
npx webpack --mode=development --watch
ビルドは下記です。
npx webpack --mode=production
公開する前には、必ずビルドを実行してください。
成功していればFigma上でRectangleを作成するサンプルプラグインが動きます。