esbuild-plugin-scriptable
An ESBuild plugin for developing Scriptable iOS app scripts with modern JavaScript tooling.
Requirements
- Node.js 14 or later
- esbuild 0.24 or later
- Scriptable iOS app with iCloud Drive sync enabled
Features
- Automatically adds Scriptable metadata banner to output files
- Supports manifest files for script configuration
- Uses manifest name as output filename (if specified)
- Handles deployment to iCloud Drive with auto-detection
- Full TypeScript support with type definitions
- File filtering with glob pattern matching
- Custom manifest path mapping
- Configurable warning behaviors
- Continues building even when deployment fails (configurable)
- Detailed deployment logging options
Installation
npm install esbuild-plugin-scriptable --save-dev
pnpm add esbuild-plugin-scriptable --save-dev
yarn add esbuild-plugin-scriptable --dev
Basic Usage
import {build} from 'esbuild';
import {scriptableBanner, scriptableDeploy} from 'esbuild-plugin-scriptable';
await build({
entryPoints: ['src/widget.ts'],
outfile: 'dist/widget.js',
bundle: true,
plugins: [
scriptableBanner({
warnOnMissingManifest: true,
patterns: '**/*.widget.ts',
}),
scriptableDeploy({
logLevel: 'verbose',
patterns: '**/*.widget.ts',
}),
],
});
Configuration
Banner Plugin Options
manifestExtensions
: Custom manifest file extensions (default: ['.manifest.json', '.manifest', '.json'])warnOnMissingManifest
: Show warning when manifest file is missing (default: true)warnOnInvalidManifest
: Show warning when manifest file is invalid (default: true)warnOnMissingEntry
: Show warning when no matching entry point is found (default: true)getManifestPath
: Custom manifest file path mapping functionpatterns
: Source file patterns to match entry points (default: ['**/*.{ts,tsx,js,jsx}'])
- Can be a string or array of strings
- Supports glob patterns with negation (! prefix)
- Examples:
'**/*.widget.ts'
- only process widget source files['**/*.ts', '!**/*.test.ts']
- exclude test files
logLevel
: Control logging detail (default: 'auto')
- 'auto': Use esbuild's logLevel
- 'silent': No logs
- 'error': Only errors
- 'warn': Errors and warnings
- 'info': Normal output
- 'verbose': Detailed output
Deploy Plugin Options
logLevel
: Control deployment logging detail (default: 'normal')
- 'silent': No logs
- 'normal': Basic deployment info
- 'verbose': Detailed deployment info
- 'debug': All deployment details
continueOnError
: Continue building when deployment fails (default: true)scriptableDir
: Custom Scriptable directory path (default: auto-detect in iCloud Drive)patterns
: Source file patterns to match entry points (default: ['**/*.{ts,tsx,js,jsx}'])
- Can be a string or array of strings
- Supports glob patterns with negation (! prefix)
- Examples:
'**/*.widget.ts'
- only deploy widget source files['**/*.ts', '!**/*.test.ts']
- exclude test files
addBanner
: Whether to add Scriptable banner from manifest (default: true)manifestExtensions
: Custom manifest file extensions (default: ['.manifest.json', '.manifest', '.json'])
Manifest Configuration
The manifest file can be used to configure both the script metadata and the output filename:
{
"name": "weather-widget",
"alwaysRunInApp": true,
"shareSheetInputs": ["file-url", "url"],
"iconColor": "blue",
"iconGlyph": "cloud",
"version": "1.0.0",
"description": "A weather widget for Scriptable"
}
When a manifest includes a name
property:
- The deploy plugin will use this name for the output file (e.g.,
weather-widget.js
) - If no name is specified, the original filename will be used
- The banner plugin will still use all manifest properties to generate the script metadata
Advanced Usage
import {build} from 'esbuild';
import {scriptableBanner, scriptableDeploy} from 'esbuild-plugin-scriptable';
await build({
entryPoints: ['src/widget.ts'],
outfile: 'dist/widget.js',
bundle: true,
plugins: [
scriptableBanner({
warnOnMissingManifest: true,
patterns: ['**/*.ts', '!**/*.test.ts'],
getManifestPath: entryPath => {
return entryPath.replace(/\.ts$/, '.manifest.json');
},
}),
scriptableDeploy({
logLevel: 'verbose',
addBanner: true,
patterns: ['**/*.ts', '!**/*.test.ts'],
scriptableDir: '/custom/path/to/Scriptable',
}),
],
});
Banner Behavior
The banner can be added in two stages:
-
Build stage (via scriptableBanner
plugin):
- Adds banner to the build output files
- Banner is part of the compiled result
-
Deploy stage (via scriptableDeploy
plugin's addBanner
option):
- Does not affect build output files
- Only adds banner to the deployed files in Scriptable directory
- Will update/override any existing banner in the target file
When using both plugins:
scriptableBanner
will add banner to build outputscriptableDeploy
with addBanner: true
will update/override the banner in deployed filesscriptableDeploy
with addBanner: false
will keep the existing banner (if any)
plugins: [
scriptableBanner({...}),
scriptableDeploy({
addBanner: true
})
]
plugins: [
scriptableDeploy({
addBanner: true
})
]
plugins: [
scriptableBanner({...}),
scriptableDeploy({
addBanner: false
})
]
The addBanner
option in scriptableDeploy
:
- Only affects the files in Scriptable directory
- Does not modify the build output files
- When
true
, will ensure the latest banner from manifest is used in deployed files - When
false
, will preserve any existing banner in the files
License
Apache-2.0