Building a Consistent UI with Meituan's Sketch Plugin: Architecture, Development, and Best Practices

Meituan Takeaway built a hybrid JavaScript‑CocoaScript Sketch plugin that enforces a unified design system, lets designers select library elements which are exported as Sketch symbols and native code components, integrates a webview bridge, uses skpm/Webpack tooling, and dramatically cuts design drift, development cost, and QA effort across multiple platforms.

Meituan Technology Team
Meituan Technology Team
Meituan Technology Team
Building a Consistent UI with Meituan's Sketch Plugin: Architecture, Development, and Best Practices

Meituan Takeaway has experienced rapid growth, but its client‑side UI components were never standardized. To solve the resulting design‑drift and high development cost, the team created a Sketch Plugin that enforces a unified design system and provides reusable components across multiple business lines.

The UI consistency project identified pain points in four layers: UI/UE (inconsistent styles), RD (fragmented component code and divergent APIs), QA (repeated manual checks), and PM (slow iteration). A shared design language—including Iconfont, color palettes, typography, and component specifications—was codified into the plugin.

The plugin works by letting designers pick elements from a predefined library; the same elements are generated as Sketch symbols and as native code components for Android, iOS, MRN, etc. Features such as data‑fill, text templates, and real‑data preview accelerate design hand‑off and reduce QA effort.

Two development approaches are possible: (1) a hybrid JavaScript + CocoaScript model that uses Sketch’s ES6‑compatible JS API, or (2) a pure Objective‑C/Swift implementation. The article follows the hybrid model.

Setup is handled by skpm (Sketch Plugin Manager). After installing the tool globally, a project can be scaffolded with a webview template:

npm install -g skpm
skpm create my-plugin --template=skpm/with-webview
npm install
npm run build

The generated directory structure looks like:

├── assets // static resources
├── my-plugin.sketchplugin // built plugin bundle
│   └── Contents
│       ├── Resources
│       │   └── resources_webview.js
│       └── Sketch
│           ├── manifest.json
│           └── __my-command.js
├── package.json
├── webpack.skpm.config.js
├── resources // source assets
│   ├── style.css
│   ├── webview.html
│   └── webview.js
└── src
    ├── manifest.json
    └── my-command.js

Key configuration files:

{
  "commands": [{
    "name": "显示工具栏",
    "identifier": "roo-sketch-plugin.toolbar",
    "script": "./script.js",
    "handlers": { "run": "showPlugin" }
  }],
  "menu": {
    "title": "🦘外卖积木SketchPlugin工具栏",
    "items": ["roo-sketch-plugin.toolbar"]
  }
}
{
  "name": "roo-sketch-plugin",
  "author": "hanyang",
  "description": "外卖积木Sketch plugin,UI同学好喜欢~",
  "version": "0.1.0",
  "skpm": {
    "manifest": "src/manifest.json",
    "main": "roo-sketch-plugin.sketchplugin",
    "assets": ["assets/**/*"]
  },
  "scripts": { "build": "rm -rf roo-sketch-plugin.sketchplugin && NODE_ENV=development skpm-build" },
  "dependencies": {},
  "devDependencies": {}
}

Creating a native toolbar in the Sketch window uses AppKit classes (NSStackView, NSButton, etc.). A minimal example:

const contentView = context.document.documentWindow().contentView();
const stageView = contentView.subviews().objectAtIndex(0);
const toolbar = NSStackView.alloc().initWithFrame(NSMakeRect(0,0,27,420));
toolbar.setBackgroundColor(NSColor.windowBackgroundColor());
toolbar.orientation = 1;
const button = NSButton.alloc().initWithFrame(rect);
button.setTitle("数据填充");
button.setFont(NSFont.fontWithName_size('Arial',11));
toolbar.addView_inGravity(button, gravityType);
stageView.addSubview(toolbar);

WebView integration can be done either manually with WKWebView or via the sketch-module-web-view helper:

import BrowserWindow from "sketch-module-web-view";
const browserWindow = new BrowserWindow(options);
const webViewContents = browserWindow.webContents;
webViewContents.executeJavaScript(`someGlobalFunction(${JSON.stringify(obj)})`).then(res => {/*...*/});
browserWindow.loadURL(require('./webview.html'));

Message passing between the UI (React/Vue) and the plugin logic uses the Bridge API. From the webview: window.postMessage('fill-text-layer', fillData); And in the plugin side:

browserWindow.webContents.on('fill-text-layer', function(s) {
  const document = context.document;
  const selection = Document.fromNative(document).selectedLayers;
  selection.layers.forEach(item => {
    if (item.type === 'Text') { item.text = s; }
  });
});

The build pipeline relies on Webpack (default for skpm). A typical rule to handle SVG files:

module.rules.push({
  test: /\.(svg)([\?].*)$/,
  use: [{ loader: "file-loader", options: { outputPath: url => path.join(WEBPACK_DIRECTORY, url), publicPath: url => url } }]
});

ESLint configuration is provided by eslint-config-sketch to support Sketch‑specific globals, and Prettier can be added for formatting.

Finally, the development workflow can be summarized as:

Implement UI logic with JavaScript/CocoaScript (or native Objective‑C/Swift).

Install NPM dependencies.

Use Bridge to forward UI actions to the plugin and call Sketch APIs.

Package with Webpack via skpm.

Test and publish the plugin.

The article ends with an invitation to join Meituan Takeaway’s tech team, highlighting that the plugin development touches front‑end, mobile, desktop, and backend skills.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptfrontend developmentplugin architectureUI consistencySketch Plugin
Meituan Technology Team
Written by

Meituan Technology Team

Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.