web-commons-export
Library for exporting presentations for Nielsen Marketing Cloud
Description
This library contains helpers for generating presentations with minimal effort using server-side rendering techniques. Using this Library, any App in Nielsen Marketing Cloud can create an export server which exposes an endpoint for generating presentations with nielsen theme (logo, background, copyright, etc) and automatic title injection, as well as automatic page counts and more.
Usage
Creating documents
- Create a directory under
documentsto hold your document. e.g:/src/documents/SegmentDocument/SegmentDocument.js.
the file exports your document creator function and unique document identifier. e.g:
export default {
documentName: 'segment',
documentCreator: async function (authorizationHeader) {
let data = await getDataAsync(authorizationHeader)
let pages = [Page1, Page2]
return {
pages,
data,
}
}
}add the document into your array of all defined documents in /documents/index.js:
import segmentDocument from './SegmentDocument/SegmentDocument'
export default [
segmentDocument
]if required, you can create a dedicated export styles file
SegmentDocument.lessand import it inSegmentDocument.js.implement the
getDataAsyncfunction to return the data required for the documentasync function getDataAsync (authorizationHeader) { const headers = { 'authorization': authorizationHeader } return fetch('http://localhost:6200/dmp/entities', {headers}) .then(res => res.json()) }define the Page classes. each class represents a Page in the presentation you export. use the
pagedecorator for built-in capabilities by the library. e.g:import { page } from 'web-export/documents' @page({ title: 'SEGMENT REPORT', bodyText:'make love not segments', theme: 'NIELSEN_SIDEBAR_AND_N', skipPageNumber: true }) class Page1 { constructor (data) { this.data = data } getMainContent () { const data = this.data return ( <SegmentViewer data={data} isExportMode /> ) } }
if you would like to build the presentation via custom code, you can expose getCustomContent method. e.g:
@page({bodyText: 'page 2 text body'})
class Page2 {
getCustomContent (slide) {
slide.addText('Title with manual location and design',
{x: '50%', y: 0.25, font_size: 18, font_face: 'Arial', color: 'FF0000'})
}
getMainContent () {
return (
<div>
Did you know? method `getMainContent` is optionally. if you use getCustomContent you may not even need it.
</div>
)
}
}read here for more details on how to write custom code.
page decorator options
| Option | Type | Default | Description | Possible Values |
|---|---|---|---|---|
title |
string | title in page header | ||
bodyText |
string | paragraph below the title | ||
skipPageNumber |
bool | false | skip the page count | true, false |
theme |
string | NIELSEN_SIDEBAR_AND_N | theme (background, logo, copyright, etc) | null, NIELSEN_SIDEBAR_AND_N |
Settings the server
The library exports setServer function which gets an express app and initializes the endpoint /export.
the function also receives array of documents and optional array of themes, and registers them.
usage example:
const express = require('express')
const {setServer} = require('web-commons-export/server')
const themes = require('web-commons-export-themes')
let documents = require('./dist/documents')
const app = express()
setServer(app, '/agen/export', documents, themes)
app.listen(9003, () => {
console.log('Export Server is listening on port 9003 ...')
})to access the /export endpoint, specify document in the query string with the document you wish to export. e.g:
https://localhost/file/agen/download/export?document=segment
Setting authentication for api requests
the export server should implement server-side jwt authentication in order to be able to perform api requests for getting data required for the export. read here for instructions.
Themes
Themes repository
There is an additional library web-commons-export-themes which acts as a decoupled repository of the common themes.
when calling setServer initialization function, you pass it the themes from this library as follows:
const themes = require('web-commons-export-themes')
setServer(app, '/agen/export', documentsRegisters, themes)Creating custom themes
If you would like to use a custom theme unique to your app across documents, you can register a new theme manually.
to do so, add it to the themes argument of the setServer function. e.g:
let copyrightTheme = {
themeId: 'NIELSEN_SIDEBAR_AND_N',
apply: function (slide) {
registerTheme('COPYRIGHT_THEME', slide => {
const copyright = `Copyright © ${new Date().getFullYear()} The Nielsen Company (US), LLC. Confidential and proprietary. Do not distribute.`
slide.addText(copyright, {
x: -2.73,
y: 4.4,
w: 5,
align: 'r',
rotate: 270,
font_size: 6,
font_face: 'Arial',
color: 'FFFFFF'
})
})
}
}
setServer(app, '/agen/export', documentsRegisters, [...themes, copyrightTheme])now you can pass it to any page in the theme property of the page decorator.
note: If you created a theme that can be useful for other NMC apps, please make a PR to the web-commons-export-themes library.
Configuring the server
Styles
The library expects the server's webpack to bundle all the styles imported into a single bundled css file.
to achieve that, you must use the ExtractTextPlugin webpack Plugin (see example).
The file location is expected to be: /dist/styles.css
Webpack loaders
The library expects the server to be able to import all required files of the app itself. to achieve that you need to configure appropriate webpack loaders (see example).
Using Infra goodness
When NMC app is loaded, the Infra injects all kind of libraries for it to use before it loads the app, such as: Underscore, React, Moment, WebInfra-Components and more.
since there is no such Infra injection for us in the export server, its our responsibility to simulate that injection for any library required by the document.
The trick is to define a global variable that would hint us that we are on server-side, and if that the case, then we inject what required. webpack conf:
plugins: [
new DefinePlugin({
__IS_SERVER_SIDE__: true
}),
...
]then in a InfraFacade.js file:
/**
* Facade for connecting with Infra
*/
let facade
// we run in Server Side
if (__IS_SERVER_SIDE__) {
// Mock window
global.window = {}
// expose underscore from the actual package, because there is no Infra to inject it globally for us
let underscore = require('underscore')
global.window._ = underscore
global._ = underscore
// import Infra components from the actual package, because there is no Infra to inject it globally for us
let InfraComponents = require('@master/webinfra-frontend-components')
facade = {InfraComponents}
}
// we run in browser
else {
// use facade which exposes the global Infra components injected for us by the Infra globally
facade = require('webapps-frontend-components/src/main/Infra/InfraFacadeShared')
}
export default facadenow in the app, we can import what required from the facade. e.g:
import { InfraComponents } from 'InfraFacade'
const { CancelButton, DetailsActionButton } = InfraComponentsNMC webapp usage example
https://github.com/xl8/web-agen-frontend/tree/master/agen-app/export-server