Migrate from jsreport
jsreport templates with the Handlebars engine and the chrome-pdf or chrome-image recipe move to
Formfeed almost unchanged: both render with Chromium, jsreport's chrome options are Formfeed's page
settings, and header and footer templates use the same pageNumber and totalPages classes. What
changes is what jsreport runs as code on your server: custom helpers and scripts.
Import templates
Export from jsreport, in the Studio (Export) or with the CLI:
jsreport export templates.jsrexport --serverUrl=https://reports.fennlor.example
In the app: Templates → Import → jsreport, choose the .jsrexport file and pick the templates.
Handlebars templates with a chrome recipe are preselected; child templates and components need no
import of their own, because they are inlined into the templates that use them. Analyse shows a
report per template, Create drafts makes a Handlebars template each.
With the CLI, in a template project:
formfeed import jsreport templates.jsrexport # every Handlebars chrome template
formfeed import jsreport templates.jsrexport --template invoices/invoice
Settings
format, width, height, landscape, the four margins, displayHeaderFooter with
headerTemplate and footerTemplate, printBackground, scale, pageRanges and
waitForNetworkIdle are mapped to the template's settings (Page setup
in the editor), and the title, author, subject and keywords of pdfMeta become the PDF
metadata. chrome-image templates become image templates with their viewport size (1200 × 630 when the
export has none), type (PNG or JPEG), quality, fullPage, and omitBackground as a transparent
background.
waitForJS (window.JSREPORT_READY_TO_START) has no direct equivalent: set
waitFor.selector in the template's settings.json or in
the settings of the API request, and let your script add that element when it is done. The editor's
settings form has no field for it. PDF passwords and
mediaType: screen are not imported; the report names both. For a password, send
post.password with the render (Starter plan and above).
jsreport's localization files are not imported either: put the texts into the template's
translations and print them with the t helper.
Assets
{{asset "logo.png" "dataURI"}} and the other encodings are resolved from the export: images and
fonts up to 256 KB become data URIs, text assets (CSS, scripts, utf8 and string encodings) are
inlined, and an asset jsreport links from an http(s) address becomes that address. Larger files,
assets the export does not contain and assets linked from the jsreport server become
{{asset "logo.png"}} and are listed in the report. Formfeed's asset
helper points at the workspace's file library: upload those files there under the
same name (on the Files page or with formfeed files push) and the references resolve. A public
HTTPS URL in their place works as well. A template that is larger than 1 MB after its assets are
inlined is an error in the report; upload the large files instead. The jsreport 2 syntax
{#asset logo.png @encoding=dataURI} is converted the same way.
Child templates
{{childTemplate "invoices/lines"}} (and jsreport 2's {#child invoices/lines}) is replaced by the
child template's content, which then renders with the same data. The report names child templates
the export does not contain.
Components
{{component "./address"}} is replaced by the component's content. Properties passed to a
component are not carried over: the inlined content sees the surrounding data, so reference those
values directly.
Helpers
Custom helpers are JavaScript that jsreport runs on your server; Formfeed does not run custom code. The report lists every helper the template defines, and every call to one is an error, because it would fail the render. Most helpers have a built-in equivalent:
| Typical jsreport helper | Formfeed |
|---|---|
| number and currency formatting | {{money total "EUR"}}, {{number qty 2}} |
| date formatting with moment | {{date issued "dd.MM.yyyy"}} |
| sums and totals | {{sum lines "total"}} |
toJS | {{{json value}}} (converted by the importer) |
| QR codes and barcodes | <img src="{{qrcode url}}" alt="QR code">, <img src="{{barcode sku type="code128"}}" alt="Barcode {{sku}}"> |
For anything else, compute the value in your application and send it with the data. The pdf-utils
helpers (pdfAddPageItem, pdfCreatePagesGroup) and module have no equivalent.
Engines
Formfeed runs Handlebars, Liquid and Jinja2. jsrender, EJS and Pug templates are imported as
Handlebars drafts with an error: rewrite them in one of the three languages. A template without an
engine (none) becomes a Handlebars template.
Recipes
chrome-pdf and chrome-image are supported, and the html recipe becomes a PDF template. Excel, Word and other recipes are reported and imported as PDF templates for reference.
Scripts
jsreport scripts (beforeRender, afterRender) usually load data before the render. Load that data
in your application and send it with the render request; Formfeed renders what it receives.
pdf-utils
Merge, append and prepend operations and headers taken from another template are not imported.
Render the parts as separate documents, or combine them in one template with page breaks
({{pageBreak}}).
Sample data
The data entity a template points at becomes its default data set; completion, the preview and the report's check for missing variables use it.
Switch the API
jsreport's POST /api/report becomes a render. The import creates drafts, and the API renders the
published version, so publish each template first. The request names the template by its slug (the
template's name in lowercase with dashes) and sends the data that jsreport's request carried:
curl https://api-eu.formfeed.dev/v1/renders \
-H "Authorization: Bearer ff_live_…" \
-H "Content-Type: application/json" \
-d '{ "template": "invoice", "data": { "number": "R-7", "total": 12.5 } }'