2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

FigmaのプラグインをWebpackで構築する

Posted at

はじめに

Figmaのプラグインを作成する環境をWebpackを使って構築する方法は、下記の公式ドキュメントで案内されてます。
Bundling with Webpack · Figma Developers

ただ、上記のドキュメントの通りにやってみたところエラーが出てしまい一部手を加えたので、備忘録的に記事に残しておきます。

1. デスクトップアプリから新しいプラグイン作成

Figmaデスクトップアプリのメニュー、plugins > Development > New plugin から新規プラグイン作成。
今回は「Figma design」の「With UI browser APIs」を選択。
image.png

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

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

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

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

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

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 を変更する。

manifest.js
{
  ...
  "main": "dist/code.js",
  "ui": "dist/ui.html",
  ...
}

5. webpackの設定

webpack.config.js を作成し、下記のように設定をする。

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.configlibdom を追加

.ts.config
"lib": ["es6", "dom"],

7. 完了

以上で完了。

開発時は、

npx webpack --mode=development --watch

ビルドは下記です。

npx webpack --mode=production

公開する前には、必ずビルドを実行してください。

成功していればFigma上でRectangleを作成するサンプルプラグインが動きます。

image.png

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?