UNPKG

14.6 kBMarkdownView Raw
1# Create Mashup App
2
3Application bootstrapper and build abstraction for rapid prototyping of Targetprocess UI mashups & integration mashups.
4
5Main philosophy is _'run 1 command and start hacking'_.
6
7While your build is performed by `create-mashup-app`, you are guaranteed to have a stable and tried build and dev server configuration that just works (hopefully) out of the box and covers most of the cases.
8
9In other words, you:
10
11- don't have to be familiar with [`tau.mashups`](https://dev.targetprocess.com/docs/create-first-mashup) API
12- don't need to write long and tiresome typescript, babel, PostCSS and other configurations
13- don't need to bang your head against the wall thinking about how to exclude modules provided by mashup API from your resulting bundle.
14
15Moreover, you can build your front-end code and serve it statically from a separate server instance running in the cluster, and manage mashup deployments by yourself.
16
17### What's included
18
19- [`babel 7`](https://github.com/rollup/rollup-plugin-babel) with latest `env` and `react` presets for using latest ES stuff and JSX, respectively. Just create a `.babelrc` in your root if you want to customize it.
20- [TypeScript](https://www.typescriptlang.org/) via [`@babel/preset-typescript`](https://babeljs.io/docs/en/babel-preset-typescript) that works out of the box. You can also specify your own `tsconfig.json`.
21- [`postcss`](https://github.com/egoist/rollup-plugin-postcss) for your CSS-related stuff, with a sprinkle of useful plugins for importing, nesting, variables, mixins and basically everything else you might want to expect from modern CSS. It also has [css modules](https://github.com/css-modules/css-modules) enabled, and appends name and version from your `package.json` to each CSS class you import so that you avoid polluting global CSS scope. It also has `inject` option set to `true`, so any styles you import magically appear as style tags on the page. Having your own `postcss.config.js` (or `.postcssrc` or any other supported config format) in root allows you to specify your own configuration.
22- Entry point wrapper for your code that calls `tau.mashups` API for you behind the scenes, adds all dependencies you list, and replaces `import`s of modules with appropriate TP mashup dependencies you mark with `provideModule`.
23- Tree-shaking that works out of the box and fast build times brought to you by [rollup](https://rollupjs.org).
24- (beta) Code splitting support and minimal external chunks loader for your mashup. You can use dynamic `import()` syntax anywhere in your code - just make sure to provide correct `baseUrl` that points to a location where your chunks are avaliable.
25
26### Installation
27
28Install globally (to generate new application):
29
30```bash
31> npm install -g create-mashup-app
32```
33
34Install as dependency (to handle build and dev server):
35
36```bash
37> cd <your-project-folder>
38> npm install --save-dev create-mashup-app
39```
40
41### Usage
42
43#### Create new app from scratch:
44
45```bash
46> create-mashup-app generate [folder]
47```
48
49This command generates a barebones mashup, with all build configuration abstracted away behind `create-mashup-app` dependency.
50
513 templates are supported as of the moment:
52
53- **minimal**
54
55`package.json`, [`mashup.json`](#mashupjson) and nothing else but your code in `src/index.js`. Bare minumum for when you need to start fresh, or when you're implimenting something relatively simple.
56
57- **react**
58
59Generates a bit more complex mashup with dummy react component that gets inserted into `document` when mashup is loaded. Includes a configured test environment and 1 dummy test, basic rules for linting and useful commands for executing them in `package.json`.
60
61- **typescript**
62
63Same as minimal, but with support for typescript enabled via [custom webpack config transform](#custom-webpack-config), appropriate `tsconfig.json` and `index.ts` as entry point.
64
65#### Build existing app:
66
67```bash
68> create-mashup-app build [folder] [--no-minify] [--no-dependency-replace] [--target=mashup] [--baseUrl=<url>]
69```
70
71This assumes that `[folder]` or current directory has correct mashup config.
72
73Build output is written to `dist` folder in `[folder]`.
74
75Build by default assumes that created mashup is used as an integration, i.e. has an integration on TP side that registers js file produced in build as `registerExternalModule`.
76
77If you want to build a mashup to be included directly into TP straight away, you can use `--target=mashup` with `create-mashup-app build`, or specify `"target": "mashup"` in your `mashup.json`.
78
79If your mashup uses dynamic imports and code splitting, be sure to provide correct `--base-url` of your chunks.
80
81#### Run development server on existing app:
82
83```bash
84> create-mashup-app devServer [folder] [--port <port>] [--no-minify] [--no-dependency-replace]
85```
86
87This assumes that `[folder]` or current directory has correct mashup config.
88
89Dev server serves your `dist` directory statically. As such, any previous build assets may be overwritten.
90
91#### Mashup configuration
92
93Your app should provide mashup configuration in any of the ways supported by [`cosmiconfig`](https://github.com/davidtheclark/cosmiconfig), i.e. via:
94
95- `mashup` property in your `package.json`
96- `.mashuprc`/`.mashuprc.json`/`.mashuprc.yaml`/`mashuprc.yml` file
97- `.mashuprc.js` or `mashup.config.js` file that exports an object
98
99`mashup.config.js` is the root configuration file for your mashup while it's controlled by `create-mashup-app`. It is generated automatically when you create a new app, and consumed every time you build or run dev server with `create-mashup-app` on an existing app.
100
101A typical mashup config will look like this:
102
103```json
104{
105 "name": "My Awesome Mashup",
106 "moduleName": "tp3/integrations/my-awesome-mashup",
107 "entry": "src/index.js",
108 "dependencies": [
109 {"mashupDependency": "react", "provideModule": "react"},
110 {"mashupDependency": "tp3/api/settings/v1"},
111 {"mashupDependency": "Underscore", "provideModule": "underscore"},
112 ...
113 ]
114}
115```
116
117Below is the breakdown for each of the fields:
118
119- `name` - This is the visible user-friendly name for your mashup. It will only be used as mashup name in Mashup Manager, so feel free to choose whatever you seem fit.
120
121- `moduleName` - This is module identifier for your mashup. While there are no theoretical boundaries on what you can use as module name, you should try to provide a technically succint namespaced value here.
122
123- `entry` - This field points to the entry point of your mashup. Typically, mashups are created by calling `tau.mashups.addDependency(...).addMashup('awesome-mashup', function(dependency) {...})`. `create-mashup-app`, however, abstracts that API away, by using dependencies from your mashup.json, simplifying their usage and adding support for bundle module replacement. The file specified in `entry` **must** contain a **named export function `initialize`**:
124
125```js
126export function initialize() {
127 console.log('I am a mashup!');
128}
129```
130
131or
132
133```js
134module.exports = {
135 initialize() {
136 console.log('I am a mashup that is afraid of using ES2015 import/export!');
137 }
138};
139```
140
141This function is called when your mashup and all of its dependencies are loaded.
142
143- `dependencies` - An array of your mashup dependencies. The list of all avaliable dependencies can be found in targetprocess [`publicModules.registry.js`](https://github.com/TargetProcess/TP/blob/develop/Code/Main/Tp.Web/JavaScript/tau/scripts/tp/publicModules.registry.js) You can specify each dependency as a string or as an object with `mashupDependency` key:
144
145```js
146...
147"dependencies": [
148 "react",
149 {"mashupDependency": "tp3/api/settings/v1"}
150]
151...
152```
153
154All mashup dependencies are available for importing as if they were regular modules. If you have a module with the same name you are importing from node_modules, it will be replaced:
155
156```js
157import TpSettings from 'tp3/api/settings/v1';
158import React from 'react';
159...
160```
161
162You can additionally specify `provideModule` key for your dependency object to create a different alias for that particular mashp module:
163
164```js
165...
166"dependencies": [
167 {"mashupDependency": "Underscore", "provideModule": "underscore"},
168 {"mashupDependency": "react", "provideModule": "tp-react"},
169 {"mashupDependency": "tp3/api/settings/v1", "provideModule": "@targetprocess/api/settings"}
170]
171...
172import _ from 'underscore'; // TP module 'Underscore' is used
173import React from 'react'; // react from your own node_modules is used
174import TpReact from 'tp-react'; // TP module 'react' is used
175import SettingsApi from '@targetprocess/api/settings'; // TP module 'tp3/api/settings/v1' is used
176```
177
178When your code is bundled normally, all node_modules imports are included with your bundle. For example, with the above code you get **entire** `react` codebase in your bundle.
179
180Some library dependencies, including `react` and `react-dom`, are already provided by TP mashup API, so carrying your own copy of React or jQuery with your mashup is very inefficient.
181
182#### Tree-shaking
183
184As of 2.0, `create-mashup-app` uses rollup for bundle generation, which statically analyzes your code for imports and exports. Refer to `https://rollupjs.org/guide/en#tree-shaking` for more details.
185
186If your bundle size is still too large, you can try to use `pureExternalModules` and `propertyReadSideEffects` rollup config options (more on them [here](https://rollupjs.org/guide/en#danger-zone)) to perform more aggressive tree-shaking.
187
188#### Code splitting
189
190Code splitting occurs whenever you use dynamic import statement in your code. Each dynamic import spawns a separate chunk that will be loaded on runtime when requested.
191`create-mashup-app` bundles a tiny dependency loader with your code that can load dynamic imports. It also requires that you build your app with `--basePath` argument and specify a correct URL where your dynamically-loaded chunks are available.
192
193Code splitting will also produce commons chunks, i.e. chunks with code that is imported by several of dynamically-loaded modules. Since there is no way to verify if commons chunk is used by your entry point chunk as of 2.0, all commons chunks are inlined with your entry point bundle, and reused lated by all dynamically loaded chunks.
194
195**(hopefully temporary) Code splitting assumes that webpage has a correct implementation of A+ Promises available from `window.Promise`. If you cannot make sure Promise is polyfilled, avoid using dynamic imports in your code.**
196
197#### ~~Providing public API~~ (temporarily broken as of 2.0 release)
198
199A mashup created by `create-mashup-app` can register public modules which can be used by other mashups. In order to provide one or more public modules, you need to perform a few things:
200
2011. Create a module which will be exposed publicly e.g. `src/api/mashup-public-api.js` with the following content:
202
203```js
204export default {
205 sayHello() {
206 console.log('hello from mashup public API');
207 }
208};
209```
210
2112. Create a javascript file which provides all public API modules exposed by the mashup, e.g. a file `src/api/index.js` with the following content:
212
213```js
214export default {
215 'tau/api/hello/v1': () => require('./mashup-public-api').default
216 // any other public modules can go here
217};
218```
219
220Keys of the exported objects are the names of the modules which can be used by other mashups.
221
222**Please note that this file should not have any dependencies in a form of `require` or `import` statements (the file is loaded and evaluated before dependencies specified in `mashup.json` are initialized)**
223
2243. Add `publicApi` property in the `mashup.json` file:
225
226```json
227{
228 ...
229 "publicApi": "src/api/index.js"
230 ...
231}
232```
233
234Now you can use this module in another mashup:
235
236```js
237tau.mashups.addDependency('tau/api/hello/v1').addMashup(function(api) {
238 api.sayHello();
239});
240```
241
242#### Customizing
243
244`create-mashup-app` is quite narrow in the way of customizing your build process. **This is intentional**. The basic idea is that you get a default configuration that just works, along with some best practices on how to handle your mashup integration.
245
246##### Custom `.babelrc`
247
248You can place `.babelrc` file in your root folder and provide your own [babel configuration](https://babeljs.io/docs/usage/babelrc/). Note that doing so will override default presets, so you'll have to include `env`, `react` and other transforms you consider useful for your app.
249
250`create-mashup-app` uses babel 7. Make sure you use correct plugin versions, e.g. `@babel/plugin-proposal-object-rest-spread` and not `babel-plugin-transform-object-rest-spread`.
251
252##### Custom PostCSS config
253
254Much like `.babelrc`, you can provide your own custom [postcss config](https://github.com/michael-ciniawsky/postcss-load-config) in any manner you seem fit. Preferred way is through `postcss.js.config`.
255
256##### Custom rollup config
257
258_Customizing rollup config generally goes a bit against the main philosophy of `create-mashup-app`. It's fine for smaller tweaks, like adding new plugins, but if you need to drastically customize build process, consider using [`eject`](#eject) instead._
259
260You can specify `configTransform` property in mashup config that points to JS file:
261
262```json
263{
264 ...
265 "configTransform": "./webpack.config.transform.js",
266}
267```
268
269or you can provide it as a function in `mashup.config.js`/`.mashuprc.js`:
270
271```js
272module.exports = {
273 name: '...',
274 ...
275 configTransform: function(config) {
276 ...
277 }
278}
279```
280
281Config transform will be invoked with basic rollup config object as parameter and is expected to return a new, transformed rollup config.
282
283For example, if youo want to add `rollup-plugin-string`, you can do it with the following transform:
284
285```js
286const string = require('rollup-plugin-string');
287
288module.exports = function(config) {
289 return {
290 ...config,
291 plugins: [
292 ...config.plugins,
293 string({
294 include: '**/*.html'
295 })
296 ]
297 };
298};
299```
300
301##### Eject
302
303**Eject is currently not supported, but will be added in future versions.**
304
305`create-mashup-app eject` will remove `create-mashup-app` from your package dependencies, transfer all required transitive dependencies to your own `package.json` and will generate all configuration files required to run build and dev server without it, much like eject in `create-react-app`.
306
307This is irreversible.