|
| 1 | +--- |
| 2 | +title: 'External Packages' |
| 3 | +description: 'Documentation for the external packages in NocoDB Scripts' |
| 4 | +icon: 'code' |
| 5 | +--- |
| 6 | + |
| 7 | +NocoDB Scripts supports importing external JavaScript packages using **dynamic imports**, allowing you to leverage NPM libraries in your scripts. |
| 8 | + |
| 9 | +<Callout type="info"> |
| 10 | +External packages are only available in browser environment and does not work in Webhook Scripts. |
| 11 | +</Callout> |
| 12 | + |
| 13 | +<Callout type="warning"> |
| 14 | +**Important:** Only dynamic imports using `import()` are supported. Static imports (e.g., `import _ from 'lodash'`) are not supported. |
| 15 | +</Callout> |
| 16 | + |
| 17 | +### Which type of imports are supported? |
| 18 | + |
| 19 | +Only dynamic imports using `import()` are supported. Static imports (`import ... from '...'`) will not work. |
| 20 | + |
| 21 | +### Can I import any NPM package? |
| 22 | + |
| 23 | +Not all packages will work. |
| 24 | + |
| 25 | +✅ **Works:** Pure JavaScript/ESM libraries (e.g., lodash, dayjs, uuid, zod, axios). |
| 26 | + |
| 27 | +❌ **Doesn't work:** Packages that require DOM (react-dom, jquery, chart.js) or Node.js APIs (fs, net, crypto Node module, express, sharp). |
| 28 | + |
| 29 | +**Tip:** If it runs inside a Web Worker, it will usually work in NocoDB Scripts. |
| 30 | + |
| 31 | +### Why do some packages fail in NocoDB Scripts? |
| 32 | + |
| 33 | +Scripts run in a Web Worker sandbox. This environment: |
| 34 | +- Has no DOM (`document`, `window`, `HTMLElement`). |
| 35 | +- Has no Node APIs (`fs`, `process`, `child_process`, native addons). |
| 36 | +- Disallows synchronous browser storage (`localStorage`, `document.cookie`). |
| 37 | + |
| 38 | +### How do I import multiple packages? |
| 39 | + |
| 40 | +Use separate dynamic imports: |
| 41 | +```javascript |
| 42 | +const _ = (await import('lodash')).default; |
| 43 | +const dayjs = (await import('dayjs')).default; |
| 44 | +``` |
| 45 | + |
| 46 | +### Do I need .default after import? |
| 47 | + |
| 48 | +Many CDN-transpiled packages expose the default export at `.default`. If you see `undefined`, try: |
| 49 | +```javascript |
| 50 | +const dayjs = (await import('dayjs')).default; |
| 51 | +``` |
| 52 | + |
| 53 | +### How do I pin a specific package version? |
| 54 | + |
| 55 | +Include a version or semver tag in the CDN URL to avoid breaking changes. |
| 56 | +```javascript |
| 57 | +const _ = (await import('https://esm.sh/lodash@4.17.21')).default; |
| 58 | +``` |
| 59 | + |
| 60 | +### Common gotchas & troubleshooting |
| 61 | + |
| 62 | +- **Named vs default exports:** Check the package's docs; you might need named imports: |
| 63 | + ```javascript |
| 64 | + const { nanoid } = await import('nanoid'); |
| 65 | + const { z } = await import('zod'); |
| 66 | + ``` |
| 67 | +- **Tree-shaking:** Import subpaths when available for smaller bundles (e.g., lodash-es functions). |
| 68 | + |
| 69 | +### Examples that work well |
| 70 | + |
| 71 | +- lodash / lodash-es |
| 72 | +- dayjs |
| 73 | +- zod |
| 74 | +- uuid |
| 75 | +- axios (uses fetch in browsers) |
| 76 | + |
| 77 | +### Examples that won't work |
| 78 | + |
| 79 | +- react-dom, jquery, chart.js, leaflet (DOM-bound) |
| 80 | +- express, fs-extra, sharp, sqlite3 (Node-only) |
| 81 | +- js-cookie (needs document.cookie) |
| 82 | + |
| 83 | +### Security considerations |
| 84 | + |
| 85 | +- Prefer pinned versions. |
| 86 | +- Review package reputation; avoid importing untrusted code at runtime. |
| 87 | +- Validate and sanitize any data flowing into third‑party libs. |
| 88 | + |
| 89 | +### Example: Full flow |
| 90 | + |
| 91 | +```javascript |
| 92 | +// Load external libs |
| 93 | +const _ = (await import('https://esm.sh/lodash@4.17.21')).default; |
| 94 | +const dayjs = (await import('https://esm.sh/dayjs@1')).default; |
| 95 | + |
| 96 | +// Query data |
| 97 | +const customers = base.getTable('Customers'); |
| 98 | +const recordQueryResult = await customers.selectRecordsAsync(); |
| 99 | + |
| 100 | +// Group and format |
| 101 | +const groupedByStatus = _.groupBy(recordQueryResult.records, r => r.getCellValue('Status')); |
| 102 | +for (const [status, customers] of Object.entries(groupedByStatus)) { |
| 103 | + output.text(`${status}: ${recordQueryResult.records.length} customers`); |
| 104 | +} |
| 105 | +output.text(`Report generated on: ${dayjs().format('MMMM D, YYYY')}`); |
| 106 | +``` |
0 commit comments