UNPKG

17.5 kBMarkdownView Raw
1# @jsreport/jsreport-core
2[![NPM Version](http://img.shields.io/npm/v/@jsreport/jsreport-core.svg?style=flat-square)](https://npmjs.com/package/@jsreport/jsreport-core)
3
4**The minimalist [jsreport](http://jsreport.net) rendering core.**
5The full distribution can be found in the [jsreport](https://npmjs.com/package/jsreport) package.
6
7[jsreport](http://jsreport.net) is a platform providing dynamic documents assembling and printing. It supports various document types or printing techniques.
8
9`@jsreport/jsreport-core` contains the jsreport rendering core that is useless alone. It is up to you which jsreport extensions you combine
10
11## Quick example
12
13To generate a document using jsreport, you always need a javascript templating engine. The **engine** is used to dynamically assemble the document based on the input values. For start lets pick [@jsreport/jsreport-handlebars](https://github.com/jsreport/jsreport/tree/master/packages/jsreport-handlebars) engine and install it using npm.
14
15Next to the engine, you need something we call **recipe**. A recipe represents the technique used to print the document. It can be an HTML to pdf conversion, DOCX rendering, and others. In this example lets pick [@jsreport/jsreport-chrome-pdf](https://github.com/jsreport/jsreport/tree/master/packages/jsreport-chrome-pdf). This recipe implements HTML to pdf conversion using [chrome](https://developers.google.com/web/updates/2017/04/headless-chrome). So in this example, we use handlebars to assemble HTML based on the input data and then print the output into the final pdf.
16
17> npm install @jsreport/jsreport-core<br/>
18> npm install @jsreport/jsreport-handlebars<br/>
19> npm install puppeteer @jsreport/jsreport-chrome-pdf
20
21```js
22const fs = require('fs').promises
23
24const jsreport = require('@jsreport/jsreport-core')()
25jsreport.use(require('@jsreport/jsreport-chrome-pdf')())
26jsreport.use(require('@jsreport/jsreport-handlebars')())
27
28await jsreport.init()
29const result = await jsreport.render({
30 template: {
31 content: '<h1>Hello {{foo}}</h1>',
32 engine: 'handlebars',
33 recipe: 'chrome-pdf'
34 },
35 data: {
36 foo: "world"
37 }
38})
39await fs.writeFile('out.pdf', result.content)
40```
41
42## Render
43`render` is the main method that invokes report generation. A single parameter is an object representing describing what to render. It has the following structure:
44```js
45{
46 //[required definition of the document]
47 template: {
48 //[required] templating engine used to assemble document
49 engine: "handlebars",
50 //[required] recipe used for printing previously assembled document
51 recipe: "chrome-pdf",
52 //[required] template for the engine
53 content: "<h1>{{foo}}</h1>",
54 //javascript helper functions used by templating engines
55 helpers: "function foo() { ...} " +
56 "function foo2() { ... }"
57 //any other settings used by recipes
58 ...
59 },
60 //dynamic data inputs used by templating engines
61 data: { foo: "hello world"}
62 ...
63}
64```
65
66In case you have the template stored in the [jsreport templates store](https://github.com/jsreport/jsreport-core#template-store), you can reference the template using a name or path.
67
68```js
69{
70 template: {
71 name: '/myfolder/mytemplate'
72 },
73 data: { foo: "hello world"}
74 ...
75}
76```
77
78The render returns a promise with the single response value
79```js
80{
81 //node.js buffer with the document
82 content: ...
83 //stream with the document
84 stream: ...
85 //object containing metadata about the report generation (reportName, logs, etc)..
86 meta: { ... }
87}
88```
89
90The convention is that jsreport repository extension starts with `jsreport-xxx`, but the extension real name and also the recipes or engines it registers excludes the `jsreport-` prefix. This means if you install extension `@jsreport/jsreport-handlebars` the engine's name you specify in the render should be `handlebars`.
91
92
93### Require in the helpers
94jsreport by default runs helpers in the sandbox where is the `require` function blocked. To unblock particular modules or local scripts you need to configure `sandbox.allowedModules` option.
95
96```js
97const jsreport = require('@jsreport/jsreport-core')({
98 sandbox: { allowedModules: ['moment'] }
99})
100
101// or unblock everything
102
103const jsreport = require('@jsreport/jsreport-core')({
104 sandbox: { allowedModules: '*' }
105})
106```
107
108Additionally, jsreport provides global variables which can be used to build the local script path and read it.
109
110```js
111const jsreport = require('@jsreport/jsreport-core')({
112 sandbox: { allowedModules: '*' }
113})
114
115await jsreport.init()
116await jsreport.render({
117 template: {
118 content: '<script>{{jquery}}</script>',
119 helpers: `
120 function jquery() {
121 const fs = require('fs')
122 const path = require('path')
123
124 return fs.readFileSync(path.join(__rootDirectory, 'jquery.js'))
125 }
126 `,
127 engine: 'handlebars',
128 recipe: 'chrome-pdf'
129 }
130})
131
132```
133
134The following variables are available in the global scope:
135
136- `__rootDirectory` - two directories up from jsreport-core
137- `__appDirectory` - directory of the script which is used when starting node
138- `__parentModuleDirectory` - directory of script which was initializing jsreport-core
139
140## Extensions
141You need to install additional packages (extensions) even for the simplest pdf printing. This is the philosophy of jsreport, and you will need to install additional extensions very often. There are many extensions adding support for persisting templates, dynamic script evaluation, adding browser based reports studio or exposing API. To get the idea of the whole platform you can install the full [jsreport](http://jsreport.net/) distribution and pick what you like. Then you can go back to `jsreport-core` and install extensions you need.
142
143You are also welcome to write your own extension or even publish it to the community. See the following articles how to get started.
144
145- [Implementing custom jsreport extension](http://jsreport.net/learn/custom-extension)
146- [Implementing custom jsreport recipe](http://jsreport.net/learn/custom-recipe)
147- [Implementing custom jsreport engine](http://jsreport.net/learn/custom-engine)
148
149The best place to find availible extensions is in the [jsreport documentation](https://jsreport.net/learn) or you can search in this [monorepo's packages](https://github.com/jsreport/jsreport/tree/master/packages) - every package with `jsreport-` prefix is an extension.
150
151## Extensions auto discovery
152jsreport by default auto-discovers extensions in the application's directory tree. This means, there is no need to explicitely `require` and call `jsreport.use` for all extensions you want to use. However it is prefered for the clarity.
153
154## Configuration
155jsreport accepts options as the first parameter. The core options are the following:
156
157```js
158require('@jsreport/jsreport-core')({
159 // optionally specifies where's the application root and where jsreport searches for extensions
160 rootDirectory: path.join(__dirname, '../../'),
161 // optionally specifies where the application stores temporary files used by the conversion pipeline
162 tempDirectory: path.join(dataDirectory, 'temp'),
163 // options for logging
164 logger: {
165 silent: false // when true, it will silence all transports defined in logger
166 },
167 // options for templating engines and other scripts execution
168 // see the https://github.com/pofider/node-script-manager for more information
169 sandbox: {
170 cache: {
171 max: 100, //LRU cache with max 100 entries, see npm lru-cache for other options
172 enabled: true //disable cache
173 }
174 },
175 loadConfig: false,
176 // the temporary files used to render reports are cleaned up by default
177 autoTempCleanup: true,
178 // set to false when you want to always force crawling node_modules when searching for extensions and starting jsreport
179 useExtensionsLocationCache: true
180})
181```
182
183`jsreport-core` is also able to load configuration from other sources including configuration file, environment variables and command line parameters. This can be opted in through option `loadConfig:true`. If this option is set to true the configuration is merged from the following sources in the particular order:
184
1851. configuration file jsreport.config.json or the one specified in `configFile` environment variable
1862. command-line arguments
1873. process environment variables
1884. options passed directly to `require('@jsreport/jsreport-core')({})`
189
190Each extension (recipe, store...) usually provides some options you can apply and adapt its behavior. These options can be typically set through standard configuration under the top-level `extensions` property, options in there with the name corresponding to the extension's name are forwarded to the particular extension. This is the common way how to globally configure all extensions at one place.
191
192```js
193require('@jsreport/jsreport-core')({
194 ...
195 "extensions": {
196 "scripts": {
197 "allowedModules": ["url"]
198 }
199 }
200})
201```
202
203You can find configuration notes for the full jsreport distribution [here](http://jsreport.net/learn/configuration).
204
205## Logging
206jsreport leverages [winston](https://github.com/winstonjs/winston) logging abstraction together with [debug](https://github.com/visionmedia/debug) utility. To output logs in the console just simply set the `DEBUG` environment variable
207
208```bash
209DEBUG=jsreport node app.js
210```
211
212on windows do
213
214```bash
215set DEBUG=jsreport & node app.js
216```
217
218To declarative configure logging levels and outputs you can see [this page](https://jsreport.net/learn/configuration#logging-configuration) which contains all the details for that.
219
220jsreport also exposes `logger` property which can be used to adapt the logging as you like. You can for example just add [winston](https://github.com/winstonjs/winston) console transport and filter in only important log messages into console.
221
222```js
223const winston = require('winston')
224const jsreport = require('@jsreport/jsreport-core')()
225jsreport.logger.add(winston.transports.Console, { level: 'info' })
226```
227
228## Typescript
229jsreport types are in the [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) repository.
230You can install [@types/jsreport-core](https://www.npmjs.com/package/@types/jsreport-core) and invidual types for extensions, or get all types at once from [@types/jsreport](https://www.npmjs.com/package/@types/jsreport).
231
232You can also find [jsreport typescript examples here](https://github.com/jsreport/jsreport-typescript-example).
233
234## Listeners
235jsreport extensions are mainly using the system of event listeners to adapt the rendering process. Extensions, can for example listen to event, which is called before the rendering process starts and adapt the input values.
236
237```js
238//jsreport must be initialized at this time
239jsreport.beforeRenderListeners.add('name-of-listener', (req, res) => {
240 req.template.content = 'Changing the template in listener!'
241})
242```
243
244To start the listening, you must first add the listener function to the right listener. In the example is used `beforeRenderListeners` which is called before the rendering starts. jsreport then in the right time sequentially fires all the listener functions and let them do the required work. If the function returns a promise, jsreport awaits until it is fulfilled.
245
246Note this technique can be used in extensions, but also outside in nodejs application using jsreport.
247
248jsreport currently support these main listeners
249
250- `initializeListeners()`- called when all extensions are initialized<br/>
251- `beforeRenderListeners(req, res)` - very first in the rendering pipeline, used to load templates and parse input data<br/>
252- `validateRenderListeners(req, res)` - possible to reject rendering before it starts, jsut return failed promise or exception<br/>
253- `afterTemplatingEnginesExecutedListeners(req, res)` - engine like handlebars or jsrender extracted the content, the `res.content` contains Buffer with extracted content<br/>
254- `afterRenderListeners(req, res)` - recipes are executed, `res.content` contains final buffer which will be returned as a stream back, the last change to modify the output or send it elsewhere<br/>
255- `renderErrorListeners(req, res, err)` - fired when there is error somewhere in the rendering pipeline
256- `closeListeners()` called when jsreport is about to be closed, you will usually put here some code that clean up some resource
257
258## Studio
259jsreport includes also visual html studio and rest API. This is provided through two extensions, [@jsreport/jsreport-express](https://github.com/jsreport/jsreport/tree/master/packages/jsreport-express) extension to have a web server available and [@jsreport/jsreport-studio](https://github.com/jsreport/jsreport/tree/master/packages/jsreport-studio) for the web UI, both extensions should be installed in order to have the studio ready. See the documentation of each extension for the details.
260
261## Template store
262`jsreport-core` includes API for persisting and accessing report templates. This API is then used by extensions mainly in combination with jsreport [studio](#studio). `jsreport-core` implements just in-memory persistence, but you can add other persistence methods through extensions, see the [template stores](https://jsreport.net/learn/template-stores) docummentation
263
264The persistence API is almost compatible to the mongodb API:
265```js
266jsreport.documentStore.collection('templates')
267 .find({name: 'test'})
268 .then((res) => {})
269
270jsreport.documentStore.collection('templates')
271 .update({name: 'test'}, { $set: { attr: 'value' })
272 .then((res) => {})
273
274jsreport.documentStore.collection('templates')
275 .insert({name: 'test'})
276 .then((res) => {})
277
278jsreport.documentStore.collection('templates')
279 .remove({name: 'test'})
280 .then((res) => {})
281```
282
283## Changelog
284
285### 3.11.4
286
287- update unset-value to fix security issue
288
289### 3.11.3
290
291- update vm2 to fix security issue
292- automatically disable full profiling after some time to avoid performance degradation
293- improvements to full profile serialization (prevent blocking)
294- fix profiles cleaning and calculate timeout in beforeRender
295
296### 3.11.2
297
298- add `options.onReqReady` to be able to receive the parsed req values
299
300### 3.11.1
301
302- fix error when trying to read `req.options` on reporter main code when `enableRequestReportTimeout` is enabled
303
304### 3.11.0
305
306- log when worker returns bad res.content
307- fix profiler leaks
308- remove settings sync API and avoid loading all items to memory
309- throw weak error when validating duplicated entity
310- ensure we end with profiles with error state when there is server or req timeout
311
312### 3.10.0
313
314- `mainReporter.executeWorkerAction` now supports cancellation with `AbortController.signal`
315- add support for specifying what are the main document properties of templates entitySet
316
317### 3.9.0
318
319- add more store methods `collection.findAdmin`, `collection.findOneAdmin`, `reporter.adminRequest` to easily allow execure store queries without taking into account permissions
320- improve logging for child requests and user level logs
321- differentiate between template not found errors and permissions related errors (it is now more clean what is the cause of specific error)
322- normalize to error when non-errors are throw (like throw "string")
323- improve errors in helpers (it now includes the helper name)
324- improve error message when template was not found in child request
325- improve error handling in sandbox
326
327### 3.8.1
328
329- update vm2 for fix security issue
330
331### 3.8.0
332
333- make "config.json" a reserved name for entities
334
335### 3.7.0
336
337- add support for multiple source entities when copying and moving
338- fix some issues with blobs and profiles
339- format user logs differently on stdout
340- fix logging of req as http.IncomingRequest
341- fix profile compatibility with jsreport container based execution
342- fix memory leak in profiling
343- add support for logs of main reporter to show in profile
344
345### 3.6.1
346
347- update @jsreport/advanced-workers to fix bug with cloning req.data when `trustUserCode` is true
348
349### 3.6.0
350
351- improve handling of worker exit
352- add a way to disable the safe execution and prevent the performance penalty
353- cache system helpers function
354- `profiler.maxDiffSize` applies to both req and res
355- improved the support for running jsreport as serverless function
356- added new apis in `jsreport-proxy` for better working with async helpers
357
358### 3.5.0
359
360- fix parsing issue of code with comment in the sandbox (helpers, scripts)
361- improve profiling when there is big data
362- make transactions support in store configurable
363- improve timeout for the whole request
364- fix applying req.options.timeout when enableRequestReportTimeout is true
365- optimization regarding profile persistence
366
367### 3.4.2
368
369- update dep `vm2` to fix security vulnerability in sandbox
370
371### 3.4.1
372
373- fix passing data to async report
374- fix blob appends
375
376### 3.4.0
377
378- fix for reports execution
379- fix for render profiling
380- fix for blob storage remove
381- update deps to fix npm audit
382
383### 3.1.0
384
385- fix blob storage append to not existing blob (mongo)
386- use relative path to the currently evaluated entity
387- fix performance issue in sandbox with long buffer (don't use restore() of sandbox through a method attached to the sandbox)
388- update migration `xlsxTemplatesToAssets`, `resourcesToAssets` to inherit permissions and change name for resource script to `${template.name}_resources`
389- refactor ListenerCollection for better stack traces
390- fix startup extensions logs not recognized as npm source
391- fix extensions cache entry root path
392- don't crash process when monitoring persist fails
393- fix compilation (updates to vm2)
394
395## License
396LGPL