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 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.htmlTextRenderEnabled`
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
- Enabled experimental HTML text rendering. By default it is `false`.
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.unstable_setTextVerticalResizeEnabled(true);
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
- ## Your own client
352
+ ## Custom Browser Arguments
311
353
 
312
- 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.
354
+ ### Using `args` export
313
355
 
314
- 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.
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
- Pass `url` option to `createInstance` function with public url of your client editor.
358
+ ```js
359
+ const { args } = require('polotno-node');
317
360
 
318
- **Note: you will have to maintain the last version of your client editor by yourself. Better to keep using the last **
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: 'KEY',
325
- url: 'https://yourappdomain.com/client',
388
+ key: 'your-key',
389
+ browser,
326
390
  });
327
391
  ```
328
392
 
329
- ## Usage on the cloud
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
- ### AWS EC2
395
+ ### Modifying default arguments
332
396
 
333
- EC2 has some troubles with loading fonts. To fix the issue install Google Chrome, it will load all required libraries.
397
+ If you need to add, remove, or replace specific arguments (Linux/macOS):
334
398
 
335
- ```bash
336
- curl https://intoli.com/install-google-chrome.sh | bash
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
- Got it from here: https://github.com/puppeteer/puppeteer/issues/765#issuecomment-353694116
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
- ### Browserless usage
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
- 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.
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
- 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.
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
- // (!) loading from polotno-node/instance will not import puppeteer and chromium-min dependencies
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: 'nFA5H9elEytDyPyvKL7T',
354
- browser: await puppeteer.connect({
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
- ### Minimal usage
446
+ ## Your own client
362
447
 
363
- 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!
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
- ```bash
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
- ```js
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
- const makeInstance = async () => {
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
- return await createInstance({
396
- key: 'your-key',
397
- browser,
398
- });
399
- };
456
+ ```js
457
+ const { createInstance } = require('polotno-node');
400
458
 
401
- const instance = await makeInstance();
459
+ const instance = await createInstance({
460
+ key: 'KEY',
461
+ url: 'https://yourappdomain.com/client',
462
+ });
402
463
  ```
403
464
 
404
- ## AWS lambda with Layer configuration
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
- - The chronium and puppeteer versions need to be satisfied. Please check this [document](https://pptr.dev/supported-browsers).
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
- How to create a configuration layer with a dependency on `chronium` ?
471
+ ```js
472
+ const { createInstance } = require('polotno-node');
424
473
 
425
- 1. Create a `.zip` file from a chronium project. For example:
474
+ export const handler = async (event) => {
475
+ const instance = await createInstance({
476
+ key: process.env.POLOTNO_API_KEY,
477
+ });
426
478
 
427
- ```shell
428
- mkdir chronium-112 && cd chronium-112
479
+ const base64 = await instance.jsonToImageBase64(event.json);
429
480
 
430
- npm init -y
431
- npm install @sparticuz/chromium@112.0
481
+ await instance.close();
432
482
 
433
- zip -r chronium.zip ./*
483
+ return {
484
+ statusCode: 200,
485
+ headers: {
486
+ 'Content-Type': 'image/png',
487
+ },
488
+ body: base64,
489
+ };
490
+ };
434
491
  ```
435
492
 
436
- 2. Go to AWS console then open a Lambda section and click on `Layers`.
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
- > Approximatelly, the size of the zip, will be around `73 Mb`, so in order to upload, the S3 service will be needed. 4. Finally, open the Lambda function, select a `Code` section, at the bottom click on `Add Layer` and select a created layer.
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
- How to run the full example with aws-cli ?
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
- ### 1. Create a Lambda configuration layer
503
+ #### AWS Lambda with Layers (Optional)
446
504
 
447
- Create a Lambda configuration layer, and upload a **.zip** archive which stores a **chronium** npm or git package.
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
- ```shell
450
- export CH_VERSION=112.0
451
- export BUCKET=example-bucket
452
- export AWS_ACC_ID=000000000000
507
+ **Dependencies:**
453
508
 
454
- # create a chronium project for Layer
455
- mkdir chronium-layer
456
- cd chronium-layer
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
- # upload a Layer to S3
462
- aws s3 cp chronium.zip s3://${BUCKET}/lambda-layers/chronium-${CH_VERSION}.zip
513
+ **Requirements:**
463
514
 
464
- # publish a Layer so it can be used in Lambda
465
- aws lambda publish-layer-version \
466
- --layer-name chronium-polotno \
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
- ### 2. Create a JS file for a Lambda's handler
519
+ **Creating a Lambda Layer with chromium:**
474
520
 
475
- #### Init a node project
521
+ 1. Create a `.zip` file from a chromium project:
476
522
 
477
523
  ```shell
478
- # create a folder
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
- # install dependencies
485
- npm install --save polotno-node puppeteer-core@19.8.0
529
+ zip -r chromium.zip ./*
486
530
  ```
487
531
 
488
- #### Create a handler
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
- ```shell
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
- return {
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
- <details>
532
- <summary>Highlighted code example from the command above:</summary>
539
+ **Handler code with custom chromium:**
540
+
541
+ Create `index.mjs`:
533
542
 
534
543
  ```js
535
- import chromium from "@sparticuz/chromium";
536
- import puppeteer from "puppeteer-core";
537
- import { createInstance } from "polotno-node";
538
- export const handler = () => {
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
- ...chromium.args,
542
- "--no-sandbox",
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
- const body = polotnoInstance.jsonToImageBase64(event.json)
563
+
564
+ const body = await polotnoInstance.jsonToImageBase64(event.json);
565
+
566
+ await polotnoInstance.close();
558
567
 
559
568
  return {
560
- StatusCode: 200,
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
- </details>
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
- ### AWS Lambda fonts issue
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
- If you have faced an issue `Timeout for loading font <font name>`, please proceed to the next solution.
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