polotno-node 2.12.29 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -237
- package/dist/assets/html2canvas.esm-Ge7aVWlp.js +5 -0
- package/dist/assets/index-vFr48NCL.js +520 -0
- package/dist/assets/{index.es-CWfYjgqJ.js → index.es-Bm4liNaR.js} +2 -15
- package/dist/assets/purify.es-C65SP4u9.js +2 -0
- package/dist/index.html +1 -1
- package/index.d.ts +2 -0
- package/index.js +53 -16
- package/instance.js +10 -13
- package/package.json +9 -8
- package/dist/assets/html2canvas.esm-B0tyYwQk.js +0 -22
- package/dist/assets/index-l_QMGoMi.js +0 -603
- package/dist/assets/purify.es-B6FQ9oRL.js +0 -2
package/README.md
CHANGED
|
@@ -67,6 +67,10 @@ const instance = await createInstance({
|
|
|
67
67
|
// useful to set your own rendering props or use browserless
|
|
68
68
|
browser: browser,
|
|
69
69
|
|
|
70
|
+
// browserArgs - additional browser arguments to append to default args
|
|
71
|
+
// see "Custom Browser Arguments" section for more details
|
|
72
|
+
browserArgs: ['--custom-arg'],
|
|
73
|
+
|
|
70
74
|
// requestInterceptor - optional function to intercept and modify network requests
|
|
71
75
|
// Useful when you need to:
|
|
72
76
|
// - Modify headers like User-Agent to access protected image resources
|
|
@@ -89,6 +93,28 @@ const instance = await createInstance({
|
|
|
89
93
|
});
|
|
90
94
|
```
|
|
91
95
|
|
|
96
|
+
### `createBrowser(options)`
|
|
97
|
+
|
|
98
|
+
Create a Puppeteer browser instance with optimized settings for Polotno rendering. This is useful when you want to create a browser separately from the instance.
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
const { createBrowser, createInstance } = require('polotno-node');
|
|
102
|
+
|
|
103
|
+
// Create a browser
|
|
104
|
+
const browser = await createBrowser({
|
|
105
|
+
browserArgs: ['--custom-arg'], // optional: additional browser arguments
|
|
106
|
+
// ... any other puppeteer.launch options
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Create instance with the browser
|
|
110
|
+
const instance = await createInstance({
|
|
111
|
+
key: 'your-key',
|
|
112
|
+
browser: browser,
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Note:** `createBrowser()` automatically uses the optimized `args` for rendering. You can add custom arguments via the `browserArgs` parameter.
|
|
117
|
+
|
|
92
118
|
### `instance.jsonToDataURL(json, attrs)`
|
|
93
119
|
|
|
94
120
|
Export json into data URL.
|
|
@@ -204,14 +230,30 @@ Timeout for loading fonts. By default it is 6000ms.
|
|
|
204
230
|
const url = await instance.jsonToPDFDataURL(json, { fontLoadTimeout: 10000 });
|
|
205
231
|
```
|
|
206
232
|
|
|
207
|
-
### `attrs.
|
|
233
|
+
### `attrs.richTextEnabled`
|
|
234
|
+
|
|
235
|
+
Enable rich text renderin. By default it is `false`.
|
|
236
|
+
|
|
237
|
+
```js
|
|
238
|
+
const url = await instance.jsonToPDFDataURL(json, {
|
|
239
|
+
richTextEnabled: true,
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### `attrs.htmlTextRenderEnabled` (deprecated)
|
|
208
244
|
|
|
209
|
-
|
|
245
|
+
⚠️ **Deprecated:** Use `richTextEnabled` instead. This property is maintained for backward compatibility and works as a fallback.
|
|
210
246
|
|
|
211
247
|
```js
|
|
248
|
+
// Old (deprecated)
|
|
212
249
|
const url = await instance.jsonToPDFDataURL(json, {
|
|
213
250
|
htmlTextRenderEnabled: true,
|
|
214
251
|
});
|
|
252
|
+
|
|
253
|
+
// New (recommended)
|
|
254
|
+
const url = await instance.jsonToPDFDataURL(json, {
|
|
255
|
+
richTextEnabled: true,
|
|
256
|
+
});
|
|
215
257
|
```
|
|
216
258
|
|
|
217
259
|
### `attrs.textVerticalResizeEnabled`
|
|
@@ -300,332 +342,245 @@ You should be able to change config before you call `store.loadJSON` function an
|
|
|
300
342
|
```js
|
|
301
343
|
const url = await instance.run(async (json) => {
|
|
302
344
|
// you can use global "config" object that has some functions from "polotno/config" module
|
|
303
|
-
window.config.
|
|
345
|
+
window.config.setTextVerticalResizeEnabled(true);
|
|
304
346
|
// you can use global "store" object
|
|
305
347
|
store.loadJSON(json);
|
|
306
348
|
return store.toDataURL();
|
|
307
349
|
}, json);
|
|
308
350
|
```
|
|
309
351
|
|
|
310
|
-
##
|
|
352
|
+
## Custom Browser Arguments
|
|
311
353
|
|
|
312
|
-
|
|
354
|
+
### Using `args` export
|
|
313
355
|
|
|
314
|
-
|
|
356
|
+
`polotno-node` exports a carefully curated set of Chrome arguments (`args`) that are optimized for server-side rendering. These arguments are automatically used when you call `createInstance()` without providing your own browser.
|
|
315
357
|
|
|
316
|
-
|
|
358
|
+
```js
|
|
359
|
+
const { args } = require('polotno-node');
|
|
317
360
|
|
|
318
|
-
|
|
361
|
+
console.log(args);
|
|
362
|
+
// Will show the default arguments like:
|
|
363
|
+
// ['--disable-web-security', '--allow-file-access-from-files', '--disable-gpu', ...]
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Platform compatibility:** Using `@sparticuz/chromium` args works best on **Linux** and **macOS**. On **Windows**, these args may not work as expected, so the library automatically skips them on Windows. When manually combining args, be aware of platform differences.
|
|
367
|
+
|
|
368
|
+
### Using with custom browser
|
|
369
|
+
|
|
370
|
+
When you want to use your own browser instance (e.g., with browserless.io or custom puppeteer configuration), you should combine `chrome.args` (the base defaults) with polotno-node's `args` (additional optimizations):
|
|
319
371
|
|
|
320
372
|
```js
|
|
321
|
-
const { createInstance } = require('polotno-node');
|
|
373
|
+
const { createInstance, args } = require('polotno-node');
|
|
374
|
+
const chromium = require('@sparticuz/chromium');
|
|
375
|
+
const puppeteer = require('puppeteer-core');
|
|
376
|
+
|
|
377
|
+
// Combine chrome.args (base defaults) with polotno-node's args (optimizations)
|
|
378
|
+
// This works best on Linux/macOS
|
|
379
|
+
const browser = await puppeteer.launch({
|
|
380
|
+
args: [...chromium.args, ...args],
|
|
381
|
+
defaultViewport: chromium.defaultViewport,
|
|
382
|
+
executablePath: await chromium.executablePath(),
|
|
383
|
+
headless: true,
|
|
384
|
+
ignoreHTTPSErrors: true,
|
|
385
|
+
});
|
|
322
386
|
|
|
323
387
|
const instance = await createInstance({
|
|
324
|
-
key: '
|
|
325
|
-
|
|
388
|
+
key: 'your-key',
|
|
389
|
+
browser,
|
|
326
390
|
});
|
|
327
391
|
```
|
|
328
392
|
|
|
329
|
-
|
|
393
|
+
**Note:** `polotno-node`'s `args` are designed to work on top of `@sparticuz/chromium`'s args for optimal server-side rendering on Linux/macOS environments.
|
|
330
394
|
|
|
331
|
-
###
|
|
395
|
+
### Modifying default arguments
|
|
332
396
|
|
|
333
|
-
|
|
397
|
+
If you need to add, remove, or replace specific arguments (Linux/macOS):
|
|
334
398
|
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
|
|
399
|
+
```js
|
|
400
|
+
const { createInstance, args } = require('polotno-node');
|
|
401
|
+
const chromium = require('@sparticuz/chromium');
|
|
402
|
+
const puppeteer = require('puppeteer-core');
|
|
338
403
|
|
|
339
|
-
|
|
404
|
+
// Add custom arguments on top of chrome.args and polotno args
|
|
405
|
+
const browser = await puppeteer.launch({
|
|
406
|
+
args: [...chromium.args, ...args, '--custom-arg', '--another-custom-arg'],
|
|
407
|
+
defaultViewport: chromium.defaultViewport,
|
|
408
|
+
executablePath: await chromium.executablePath(),
|
|
409
|
+
});
|
|
340
410
|
|
|
341
|
-
|
|
411
|
+
// Remove specific arguments from polotno args
|
|
412
|
+
const filteredArgs = args.filter((arg) => arg !== '--disable-gpu');
|
|
413
|
+
const browser2 = await puppeteer.launch({
|
|
414
|
+
args: [...chromium.args, ...filteredArgs],
|
|
415
|
+
defaultViewport: chromium.defaultViewport,
|
|
416
|
+
executablePath: await chromium.executablePath(),
|
|
417
|
+
});
|
|
342
418
|
|
|
343
|
-
|
|
419
|
+
// Replace specific arguments in polotno args
|
|
420
|
+
const customArgs = args.map((arg) =>
|
|
421
|
+
arg === '--disable-web-security' ? '--enable-web-security' : arg
|
|
422
|
+
);
|
|
423
|
+
const browser3 = await puppeteer.launch({
|
|
424
|
+
args: [...chromium.args, ...customArgs],
|
|
425
|
+
defaultViewport: chromium.defaultViewport,
|
|
426
|
+
executablePath: await chromium.executablePath(),
|
|
427
|
+
});
|
|
428
|
+
```
|
|
344
429
|
|
|
345
|
-
|
|
430
|
+
**Note:** These examples assume Linux/macOS environment where `chromium.args` work properly.
|
|
431
|
+
|
|
432
|
+
### Combining with `browserArgs` option
|
|
433
|
+
|
|
434
|
+
When using `createInstance()` or `createBrowser()`, you can provide additional arguments via `browserArgs` option. Internally, this automatically combines `chrome.args` + `args` + your custom `browserArgs`:
|
|
346
435
|
|
|
347
436
|
```js
|
|
348
|
-
|
|
349
|
-
const { createInstance } = require('polotno-node/instance');
|
|
350
|
-
const puppeteer = require('puppeteer');
|
|
437
|
+
const { createInstance } = require('polotno-node');
|
|
351
438
|
|
|
352
439
|
const instance = await createInstance({
|
|
353
|
-
key: '
|
|
354
|
-
|
|
355
|
-
browserWSEndpoint: 'wss://chrome.browserless.io?token=API_KEY',
|
|
356
|
-
}),
|
|
357
|
-
url: 'https://yourappdomain.com/client', // see "Your own client" section
|
|
440
|
+
key: 'your-key',
|
|
441
|
+
browserArgs: ['--custom-arg', '--another-arg'],
|
|
358
442
|
});
|
|
443
|
+
// Internally merges: chrome.args + polotno args + browserArgs
|
|
359
444
|
```
|
|
360
445
|
|
|
361
|
-
|
|
446
|
+
## Your own client
|
|
362
447
|
|
|
363
|
-
|
|
448
|
+
By default `polotno-node` ships with the default Polotno Editor with its (hopefully) last version. If you use experimental API such as `unstable_registerShapeModel` and `unstable_registerShapeComponent`, the rendering may fail if you use unknown elements types.
|
|
364
449
|
|
|
365
|
-
|
|
366
|
-
npm install @sparticuz/chromium-min
|
|
367
|
-
```
|
|
450
|
+
In that case you can use your own client editor. You need to create a public html page with `store` as global variable and mount just `<Workspace />` component from `polotno/canvas` module. Take a look into `client.html` file and `client.js` file in this repo as a demo. In your own version of the Editor you can use experimental API to define custom components.
|
|
368
451
|
|
|
369
|
-
|
|
370
|
-
const { createInstance } = require('polotno-node/instance');
|
|
371
|
-
const chromium = require('@sparticuz/chromium-min');
|
|
372
|
-
const puppeteer = require('puppeteer-core');
|
|
452
|
+
Pass `url` option to `createInstance` function with public url of your client editor.
|
|
373
453
|
|
|
374
|
-
|
|
375
|
-
const browser = await puppeteer.launch({
|
|
376
|
-
args: [
|
|
377
|
-
...chromium.args,
|
|
378
|
-
'--no-sandbox',
|
|
379
|
-
'--hide-scrollbars',
|
|
380
|
-
'--disable-web-security',
|
|
381
|
-
'--allow-file-access-from-files',
|
|
382
|
-
// more info about --disable-dev-shm-usage
|
|
383
|
-
// https://github.com/puppeteer/puppeteer/issues/1175#issuecomment-369728215
|
|
384
|
-
// https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#tips
|
|
385
|
-
'--disable-dev-shm-usage',
|
|
386
|
-
],
|
|
387
|
-
defaultViewport: chromium.defaultViewport,
|
|
388
|
-
executablePath: await chromium.executablePath(
|
|
389
|
-
'https://github.com/Sparticuz/chromium/releases/download/v110.0.1/chromium-v110.0.1-pack.tar'
|
|
390
|
-
),
|
|
391
|
-
headless: chromium.headless,
|
|
392
|
-
ignoreHTTPSErrors: true,
|
|
393
|
-
});
|
|
454
|
+
**Note: you will have to maintain the last version of your client editor by yourself. Better to keep using the last **
|
|
394
455
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
browser,
|
|
398
|
-
});
|
|
399
|
-
};
|
|
456
|
+
```js
|
|
457
|
+
const { createInstance } = require('polotno-node');
|
|
400
458
|
|
|
401
|
-
const instance = await
|
|
459
|
+
const instance = await createInstance({
|
|
460
|
+
key: 'KEY',
|
|
461
|
+
url: 'https://yourappdomain.com/client',
|
|
462
|
+
});
|
|
402
463
|
```
|
|
403
464
|
|
|
404
|
-
##
|
|
405
|
-
|
|
406
|
-
In order to run the **polotno-node** in AWS Lambda, it's recommended to use a [Lambda Layer configurations](https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html) which will manage the dependencies, like **chronium**.
|
|
407
|
-
In addition, the Lambda's configuration needs to be changed as well. It's recommeded to change the **timeout** to 30 seconds instead of default value (3 seconds) and **Memory limit** increase to minimum 512 Mb instead of 128 mb ( default value ).
|
|
408
|
-
|
|
409
|
-
Dependencies:
|
|
410
|
-
|
|
411
|
-
- @sparticuz/chromium
|
|
412
|
-
- puppeteer-core
|
|
413
|
-
- polotno-node
|
|
414
|
-
|
|
415
|
-
Pre-requirements:
|
|
465
|
+
## Usage on the cloud
|
|
416
466
|
|
|
417
|
-
|
|
418
|
-
- The **minumum Memory limit** needs to be `512 Mb` for AWS Lambda. Default is `128 Mb`.
|
|
419
|
-
- The **timeout** should be increased from default 3 seconds to higher value, for example up to 30 seconds. It depends on the Memory limit. For instance, if the memory limit was set to 1024, the polotno process might take ~15 secs, if 512 mb, ~30sec.
|
|
467
|
+
### AWS Lambda
|
|
420
468
|
|
|
421
|
-
|
|
469
|
+
`polotno-node` works with AWS Lambda out of the box. Here's a simple example:
|
|
422
470
|
|
|
423
|
-
|
|
471
|
+
```js
|
|
472
|
+
const { createInstance } = require('polotno-node');
|
|
424
473
|
|
|
425
|
-
|
|
474
|
+
export const handler = async (event) => {
|
|
475
|
+
const instance = await createInstance({
|
|
476
|
+
key: process.env.POLOTNO_API_KEY,
|
|
477
|
+
});
|
|
426
478
|
|
|
427
|
-
|
|
428
|
-
mkdir chronium-112 && cd chronium-112
|
|
479
|
+
const base64 = await instance.jsonToImageBase64(event.json);
|
|
429
480
|
|
|
430
|
-
|
|
431
|
-
npm install @sparticuz/chromium@112.0
|
|
481
|
+
await instance.close();
|
|
432
482
|
|
|
433
|
-
|
|
483
|
+
return {
|
|
484
|
+
statusCode: 200,
|
|
485
|
+
headers: {
|
|
486
|
+
'Content-Type': 'image/png',
|
|
487
|
+
},
|
|
488
|
+
body: base64,
|
|
489
|
+
};
|
|
490
|
+
};
|
|
434
491
|
```
|
|
435
492
|
|
|
436
|
-
|
|
437
|
-
3. Following the [documentation](https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html) create a Layer with a chrnioum dependency by uploading a zip file. Keep in mind that environment like `nodejs18.x` should match between layer and function.
|
|
493
|
+
**Important:** For reliable performance, you may need to increase AWS Lambda limits:
|
|
438
494
|
|
|
439
|
-
|
|
495
|
+
- **Memory**: Increase from the default. For complex designs, you may need to set it to maximum.
|
|
496
|
+
- **Timeout**: Increase from the default. For large files, you may need to set it to maximum.
|
|
497
|
+
- **Ephemeral Storage**: May need to increase from the default for complex designs.
|
|
440
498
|
|
|
441
|
-
|
|
499
|
+
Without these increases, polotno-node may work on smaller files but will fail or timeout on larger files.
|
|
442
500
|
|
|
443
|
-
|
|
501
|
+
**Full working example:** See [polotno-node-aws-lambda](https://github.com/polotno-project/polotno-node-aws-lambda) for a complete demo.
|
|
444
502
|
|
|
445
|
-
|
|
503
|
+
#### AWS Lambda with Layers (Optional)
|
|
446
504
|
|
|
447
|
-
|
|
505
|
+
For advanced usage, you can use [Lambda Layers](https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html) to manage dependencies like chromium separately. This can help with deployment size and organization.
|
|
448
506
|
|
|
449
|
-
|
|
450
|
-
export CH_VERSION=112.0
|
|
451
|
-
export BUCKET=example-bucket
|
|
452
|
-
export AWS_ACC_ID=000000000000
|
|
507
|
+
**Dependencies:**
|
|
453
508
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
npm init -y
|
|
458
|
-
npm install @sparticuz/chromium@${CH_VERSION}
|
|
459
|
-
zip -r chronium.zip ./*
|
|
509
|
+
- @sparticuz/chromium
|
|
510
|
+
- puppeteer-core
|
|
511
|
+
- polotno-node
|
|
460
512
|
|
|
461
|
-
|
|
462
|
-
aws s3 cp chronium.zip s3://${BUCKET}/lambda-layers/chronium-${CH_VERSION}.zip
|
|
513
|
+
**Requirements:**
|
|
463
514
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
--content "S3Bucket=${BUCKET},S3Key=lambda-layers/chronium-{CH_VERSION}.zip" \
|
|
468
|
-
--description Chronium-dev-${CH_VERSION} \
|
|
469
|
-
--compatible-architectures x86_64 \
|
|
470
|
-
--compatible-runtimes nodejs18.x
|
|
471
|
-
```
|
|
515
|
+
- The chromium and puppeteer versions need to be compatible. Please check this [document](https://pptr.dev/supported-browsers).
|
|
516
|
+
- The **Memory limit** needs to be increased from the default. You may need to set it to maximum for complex designs.
|
|
517
|
+
- The **timeout** should be increased from the default. You may need to set it to maximum for large files.
|
|
472
518
|
|
|
473
|
-
|
|
519
|
+
**Creating a Lambda Layer with chromium:**
|
|
474
520
|
|
|
475
|
-
|
|
521
|
+
1. Create a `.zip` file from a chromium project:
|
|
476
522
|
|
|
477
523
|
```shell
|
|
478
|
-
|
|
479
|
-
mkdir handler && cd handler
|
|
524
|
+
mkdir chromium-112 && cd chromium-112
|
|
480
525
|
|
|
481
|
-
# init a node project
|
|
482
526
|
npm init -y
|
|
527
|
+
npm install @sparticuz/chromium@112.0
|
|
483
528
|
|
|
484
|
-
|
|
485
|
-
npm install --save polotno-node puppeteer-core@19.8.0
|
|
529
|
+
zip -r chromium.zip ./*
|
|
486
530
|
```
|
|
487
531
|
|
|
488
|
-
|
|
532
|
+
2. Go to AWS console then open Lambda section and click on `Layers`.
|
|
533
|
+
3. Following the [documentation](https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html) create a Layer with a chromium dependency by uploading a zip file. Keep in mind that environment like `nodejs18.x` should match between layer and function.
|
|
489
534
|
|
|
490
|
-
|
|
491
|
-
# create a file handler
|
|
492
|
-
touch index.mjs
|
|
493
|
-
|
|
494
|
-
# add code example
|
|
495
|
-
echo "
|
|
496
|
-
import chromium from "@sparticuz/chromium";
|
|
497
|
-
import puppeteer from "puppeteer-core";
|
|
498
|
-
import { createInstance } from "polotno-node";
|
|
499
|
-
export const handler = () => {
|
|
500
|
-
const browser = await puppeteer.launch({
|
|
501
|
-
args: [
|
|
502
|
-
...chromium.args,
|
|
503
|
-
"--no-sandbox",
|
|
504
|
-
"--hide-scrollbars",
|
|
505
|
-
"--disable-web-security",
|
|
506
|
-
"--allow-file-access-from-files",
|
|
507
|
-
"--disable-dev-shm-usage",
|
|
508
|
-
],
|
|
509
|
-
defaultViewport: chromium.defaultViewport,
|
|
510
|
-
executablePath: await chromium.executablePath(),
|
|
511
|
-
headless: true,
|
|
512
|
-
ignoreHTTPSErrors: true,
|
|
513
|
-
});
|
|
514
|
-
const polotnoInstance = await createInstance({
|
|
515
|
-
key: process.env.POLOTNO_API_KEY,
|
|
516
|
-
browser,
|
|
517
|
-
});
|
|
518
|
-
const body = polotnoInstance.jsonToImageBase64(event.json)
|
|
535
|
+
> The size of the zip will be large, so you may need to use S3 to upload it.
|
|
519
536
|
|
|
520
|
-
|
|
521
|
-
StatusCode: 200,
|
|
522
|
-
headers: {
|
|
523
|
-
'Content-Type': 'image/png'
|
|
524
|
-
},
|
|
525
|
-
body,
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
" >> index.mjs
|
|
529
|
-
```
|
|
537
|
+
4. Finally, open the Lambda function, select a `Code` section, at the bottom click on `Add Layer` and select a created layer.
|
|
530
538
|
|
|
531
|
-
|
|
532
|
-
|
|
539
|
+
**Handler code with custom chromium:**
|
|
540
|
+
|
|
541
|
+
Create `index.mjs`:
|
|
533
542
|
|
|
534
543
|
```js
|
|
535
|
-
import chromium from
|
|
536
|
-
import puppeteer from
|
|
537
|
-
import { createInstance } from
|
|
538
|
-
|
|
544
|
+
import chromium from '@sparticuz/chromium';
|
|
545
|
+
import puppeteer from 'puppeteer-core';
|
|
546
|
+
import { createInstance, args } from 'polotno-node';
|
|
547
|
+
|
|
548
|
+
export const handler = async (event) => {
|
|
539
549
|
const browser = await puppeteer.launch({
|
|
540
|
-
args
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
"--hide-scrollbars",
|
|
544
|
-
"--disable-web-security",
|
|
545
|
-
"--allow-file-access-from-files",
|
|
546
|
-
"--disable-dev-shm-usage",
|
|
547
|
-
],
|
|
550
|
+
// Combine chromium args with polotno-node's optimized args
|
|
551
|
+
// Works well on AWS Lambda (Linux environment)
|
|
552
|
+
args: [...chromium.args, ...args],
|
|
548
553
|
defaultViewport: chromium.defaultViewport,
|
|
549
554
|
executablePath: await chromium.executablePath(),
|
|
550
555
|
headless: true,
|
|
551
556
|
ignoreHTTPSErrors: true,
|
|
552
557
|
});
|
|
558
|
+
|
|
553
559
|
const polotnoInstance = await createInstance({
|
|
554
560
|
key: process.env.POLOTNO_API_KEY,
|
|
555
561
|
browser,
|
|
556
562
|
});
|
|
557
|
-
|
|
563
|
+
|
|
564
|
+
const body = await polotnoInstance.jsonToImageBase64(event.json);
|
|
565
|
+
|
|
566
|
+
await polotnoInstance.close();
|
|
558
567
|
|
|
559
568
|
return {
|
|
560
|
-
|
|
569
|
+
statusCode: 200,
|
|
561
570
|
headers: {
|
|
562
|
-
'Content-Type': 'image/png'
|
|
571
|
+
'Content-Type': 'image/png',
|
|
563
572
|
},
|
|
564
573
|
body,
|
|
565
|
-
}
|
|
574
|
+
};
|
|
566
575
|
};
|
|
567
576
|
```
|
|
568
577
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
#### Create file with variables
|
|
572
|
-
|
|
573
|
-
```shell
|
|
574
|
-
echo '{
|
|
575
|
-
"Variables": {
|
|
576
|
-
"POLOTNO_API_KEY": "your-api-key"
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
' >> vars.json
|
|
580
|
-
|
|
581
|
-
# archive the folder
|
|
582
|
-
zip -r index.zip ./*
|
|
583
|
-
|
|
584
|
-
# copy to S3
|
|
585
|
-
aws s3 cp index.zip s3://${BUCKET}/polotno-handler.zip
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
#### Crete a trust policy
|
|
589
|
-
|
|
590
|
-
```shell
|
|
591
|
-
echo '{
|
|
592
|
-
"Version": "2012-10-17",
|
|
593
|
-
"Statement": [
|
|
594
|
-
{
|
|
595
|
-
"Effect": "Allow",
|
|
596
|
-
"Principal": {
|
|
597
|
-
"Service": "lambda.amazonaws.com"
|
|
598
|
-
},
|
|
599
|
-
"Action": "sts:AssumeRole"
|
|
600
|
-
}
|
|
601
|
-
]
|
|
602
|
-
}
|
|
603
|
-
' >> trustPolicy.json
|
|
604
|
-
```
|
|
605
|
-
|
|
606
|
-
#### Create roles and policies in AWS
|
|
607
|
-
|
|
608
|
-
```shell
|
|
609
|
-
aws iam create-role --role-name lambda-polotno-role --assume-role-policy-document file://trustPolicy.json
|
|
610
|
-
aws iam attach-role-policy --role-name lambda-polotno-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
|
|
611
|
-
aws lambda create-function --function-name lambda-polotno \
|
|
612
|
-
--runtime nodejs18.x \
|
|
613
|
-
--zip-file fileb://index.zip \
|
|
614
|
-
--layers "arn:aws:lambda:eu-central-1:${AWS_ACC_ID}:layer:chronium-polotno:1" \
|
|
615
|
-
--handler index.handler \
|
|
616
|
-
--environment file://vars.json \
|
|
617
|
-
--role "arn:aws:iam::${AWS_ACC_ID}:role/lambda-polotno-role" \
|
|
618
|
-
--timeout 60 \
|
|
619
|
-
--memory-size 512
|
|
620
|
-
// try it
|
|
621
|
-
aws lambda invoke --function-name lambda-polotno --cli-binary-format raw-in-base64-out --payload file://polotno-project-json.json image
|
|
622
|
-
```
|
|
578
|
+
#### AWS Lambda fonts issue
|
|
623
579
|
|
|
624
|
-
|
|
580
|
+
Lambda functions do not include any fonts by default. If you encounter `Timeout for loading font <font name>` errors, you need to provide basic fonts (Arial and Times or their analogs).
|
|
625
581
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
Lambda functions does not include any fonts by default, so we need to provide basic fonts (Arial and Times or their analogs) to make sure Polotno fonts functionality is working correctly.
|
|
582
|
+
<details>
|
|
583
|
+
<summary>Solution: Add fonts to your Lambda function</summary>
|
|
629
584
|
|
|
630
585
|
1. Create a `fonts` folder in the root of your handler project.
|
|
631
586
|
|
|
@@ -662,6 +617,75 @@ mkdir fonts
|
|
|
662
617
|
|
|
663
618
|
4. Upload your Lambda function as usual, fonts will be loaded automatically.
|
|
664
619
|
|
|
620
|
+
</details>
|
|
621
|
+
|
|
622
|
+
### AWS EC2
|
|
623
|
+
|
|
624
|
+
EC2 has some troubles with loading fonts. To fix the issue install Google Chrome, it will load all required libraries.
|
|
625
|
+
|
|
626
|
+
```bash
|
|
627
|
+
curl https://intoli.com/install-google-chrome.sh | bash
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
Got it from here: https://github.com/puppeteer/puppeteer/issues/765#issuecomment-353694116
|
|
631
|
+
|
|
632
|
+
### Browserless usage
|
|
633
|
+
|
|
634
|
+
You can speed up your function execution a lot, if instead of using full browser you will use [browserless.io](https://browserless.io/) service. It is a paid service not affiliated with Polotno.
|
|
635
|
+
|
|
636
|
+
Using browserless.io you can also make your function much smaller in size, so it will be possible to deploy to cloud provider with smaller limits, like Vercel.
|
|
637
|
+
|
|
638
|
+
```js
|
|
639
|
+
// (!) loading from polotno-node/instance will not import puppeteer and chromium-min dependencies
|
|
640
|
+
const { createInstance } = require('polotno-node/instance');
|
|
641
|
+
const puppeteer = require('puppeteer');
|
|
642
|
+
|
|
643
|
+
const instance = await createInstance({
|
|
644
|
+
key: 'nFA5H9elEytDyPyvKL7T',
|
|
645
|
+
browser: await puppeteer.connect({
|
|
646
|
+
browserWSEndpoint: 'wss://chrome.browserless.io?token=API_KEY',
|
|
647
|
+
}),
|
|
648
|
+
url: 'https://yourappdomain.com/client', // see "Your own client" section
|
|
649
|
+
});
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### Minimal usage
|
|
653
|
+
|
|
654
|
+
Also you can use [@sparticuz/chromium-min](https://github.com/Sparticuz/chromium#-min-package) to reduce function size. Make sure it is caching chromium binary in your cloud provider. Looks like Vercel is NOT doing that!
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
npm install @sparticuz/chromium-min
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
```js
|
|
661
|
+
const { createInstance } = require('polotno-node/instance');
|
|
662
|
+
// Import args from main entry point for optimal browser configuration
|
|
663
|
+
const { args } = require('polotno-node');
|
|
664
|
+
const chromium = require('@sparticuz/chromium-min');
|
|
665
|
+
const puppeteer = require('puppeteer-core');
|
|
666
|
+
|
|
667
|
+
const makeInstance = async () => {
|
|
668
|
+
const browser = await puppeteer.launch({
|
|
669
|
+
// Combine chromium args with polotno-node's optimized args
|
|
670
|
+
// Best for Linux/macOS environments
|
|
671
|
+
args: [...chromium.args, ...args],
|
|
672
|
+
defaultViewport: chromium.defaultViewport,
|
|
673
|
+
executablePath: await chromium.executablePath(
|
|
674
|
+
'https://github.com/Sparticuz/chromium/releases/download/v110.0.1/chromium-v110.0.1-pack.tar'
|
|
675
|
+
),
|
|
676
|
+
headless: chromium.headless,
|
|
677
|
+
ignoreHTTPSErrors: true,
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
return await createInstance({
|
|
681
|
+
key: 'your-key',
|
|
682
|
+
browser,
|
|
683
|
+
});
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
const instance = await makeInstance();
|
|
687
|
+
```
|
|
688
|
+
|
|
665
689
|
## Troubleshooting
|
|
666
690
|
|
|
667
691
|
If you have an error like this
|