1- # Plugins
1+ # < a name = " plugins " ></ a > Plugins
22
3- Scully uses a plugin system to allow users to define new ways for Scully to build your app. There are two main types of
4- plugins:
3+ Scully uses a plugin system to allow users to define new ways for Scully to pre-render your app. There are three main
4+ types of plugins:
55
6- 1 . [ Route Plugins] ( #route-plugins )
7- 2 . [ Data Transform Plugins] ( #transform-plugins )
6+ 1 . [ Router Plugins] ( #router-plugin )
7+ 2 . [ Render Plugins] ( #render-plugin )
8+ 3 . [ File Handler Plugins] ( #file-plugin )
89
910See our [ Recommended Plugins] ( recommended-plugins.md ) page to find a list of available plugins.
1011
11- ## < a name = " route-plugins " ></ a > Route Plugins
12+ ---
1213
13- Scully needs __ Route Plugins__ to discover data needed to pre-render your app's views. Any route that has a route
14- parameter in it will require you to configure a plugin that teaches Scully how to get the data needed for those route
15- parameters.
14+ ## <a name =" router-plugin " ></a > Router Plugins
1615
17- Let's look at an example. Suppose your app has a route ` {path: 'user/:userId', component: UserComponent} ` . In order for
18- Scully to pre-render your app, it needs to know the complete list of User IDs that will be used in that route parameter
19- ` :userId ` . If your app had 5 users with the IDs 1, 2, 3, 4, and 5, then Scully would need to render the following routes:
16+ ### <a name =" router-plugin-what-is " ></a > What is a Router Plugin?
17+
18+ Scully needs __ router plugins__ to discover data needed to pre-render your app's views. Any route that has a route
19+ parameter in it will require you to configure a __ router plugin__ that teaches Scully how to get the data needed for
20+ those route parameters.
21+
22+ Suppose your app has a route ` {path: 'user/:userId', component: UserComponent} ` . In order for Scully to pre-render your
23+ app, it needs to know the complete list of User IDs that will be used in that route parameter ` :userId ` . If your app
24+ had 5 users with the IDs 1, 2, 3, 4, and 5, then Scully would need to render the following routes:
2025```
21- /user/10
22- /user/11
23- /user/12
24- /user/13
25- /user/14
26+ /user/1
27+ /user/2
28+ /user/3
29+ /user/4
30+ /user/5
2631```
2732
28- To provide this list of User IDs to Scully, you'll use a __ Route Plugins__ .
33+ A __ router plugin__ is used to convert the raw route config into a list of routes that scully can then crawl/render.
34+
35+ ### <a name =" router-plugin-interface " ></a > Router Plugin Interface
36+
37+ A __ router plugin__ is a function that returns a ` Promise<HandledRoute[]> ` . Let's look at the interface of the route
38+ plugin as well as the ` HandledRoute ` .
39+
40+ ``` typescript
41+ interface HandledRoute {
42+ route: string ;
43+ }
44+
45+ function exampleRouterPlugin(route : string , config : any ) : Promise <HandledRoute []> {
46+ // must return a promise here
47+ }
48+ ```
49+
50+ The ` HandledRoute[] ` gets added into the ` scully-routes.json ` that is generated when you run ` npm run scully ` .
51+
52+ ### <a name =" router-plugin-how-to " ></a > How To Make A Router Plugin
53+ In our previous example of an app with the route ` /user/:userId ` where we have five distinct userIds, here is a __ router
54+ plugin__ that would turn the raw route into five distinct HandledRoutes.
55+
56+ ``` typescript
57+ function userIdPlugin(route : string , config = {}): Promise <HandledRoute []> {
58+ return Promise .resolve (
59+ [
60+ { route: ' /user/1' },
61+ { route: ' /user/2' },
62+ { route: ' /user/3' },
63+ { route: ' /user/4' },
64+ { route: ' /user/5' },
65+ ]
66+ );
67+ }
68+ // DON'T FORGET THIS STEP
69+ registerPlugin (' router' , ' userIds' , userIdPlugin );
70+ ```
71+
72+ Once we have built a plugin, we can configure our ` scully.config.js ` to use our plugin.
73+
74+ ### <a name =" router-plugin-configure " ></a > How To Configure A Router Plugin
75+
76+ The following configuration uses our ` userIds ` router plugin to get the ` HandledRoute[] ` for our app:
77+
78+ ``` javascript
79+ // scully.config.js
80+ exports .config = {
81+ // Add the following to your file
82+ routes: {
83+ " /user/:userId" : {
84+ " type" : " userIds" ,
85+ }
86+ }
87+ };
88+ ```
2989
3090The following is an example that uses the [ jsonplaceholder] ( https://jsonplaceholder.typicode.com/ ) to fetch a list of
31- User IDs for my app.
91+ User IDs for my app. It uses the ` json ` plugin.
3292
3393``` javascript
3494// scully.config.js
@@ -53,10 +113,120 @@ second is `property`. The JSON plugin will pluck the provided property name fro
53113means that the array returned by the jsonplaceholder api will each have an ` id ` property. So instead of returning a list
54114users, it will return a list of userIds.
55115
116+ ### <a name =" router-plugin-configure " ></a > Router Plugin Examples
117+ For those looking to build router plugins for their app, here are links to the built-in __ router plugins__ in Scully:
118+ - [ JSON Plugin] ( ../scully/routerPlugins/jsonRoutePlugin.ts )
119+ - [ Content Folder Plugin] ( ../scully/routerPlugins/contentFolderPlugin.ts )
120+
121+ [ Back to top] ( #plugins )
122+
123+ ---
124+
125+ ## <a name =" render-plugin " ></a > Render Plugins
56126
57- ## <a name =" transform-plugins " ></a > Data Transform Plugins
127+ ### <a name =" render-plugin-what-is " ></a > What is a Render Plugin?
128+
129+ A __ render plugin__ is used to transform the HTML that your app rendered. After your Angular app renders the page,
130+ that rendered content/HTML is passed to a __ render plugin__ where it can be further modified. An example of why you
131+ would want to use a render plugin: to transform a page that contains markdown into a page that contains the rendered
132+ markdown.
133+
134+ ### <a name =" render-plugin-interface " ></a > Render Plugin Interface
135+
136+ A __ render plugin__ is a function that returns a ` Promise<String> ` . The string in the promise must be the transformed
137+ HTML. Here is what the interface looks like:
138+ ``` typescript
139+ function exampleContentPlugin(HTML : string , route : HandledRoute ) : Promise <string > {
140+ // must return a promise here
141+ }
142+ ```
143+
144+ ### <a name =" render-plugin-how-to " ></a > How To Make A Render Plugin
145+ The following is a sample __ render plugin__ that adds a title to the head of a page if it doesn't find one.
146+
147+ ``` ecmascript 6
148+ function defaultTitlePlugin(html, route) {
149+ // If no title in the document
150+ if(html.indexOf('<title') < 0) {
151+ const splitter = '</head>';
152+ const [begin, end] = html.split(splitter);
153+ const defaultTitle = `<title>The Truth Is Out There!</title>`;
154+ return Promise.resolve(`${begin}${defaultTitle}${splitter}${end}`);
155+ }
156+ return Promise.resolve(html);
157+ }
158+ // DON'T FORGET THIS STEP
159+ registerPlugin('render', 'defaultTitle', defaultTitlePlugin);
160+ ```
161+
162+ In this example, the HTML that the Angular app rendered is transformed to include a title (if one wasn't found). This
163+ is the primary function of a render plugin.
164+
165+ Here is another example that would replace any instances of ` :) ` with a smiley emoji:
166+
167+ ``` ecmascript 6
168+ function smileEmojiPlugin(html, route) {
169+ return Promise.resolve(html.replace(/\:\)/g, '😊'));
170+ }
171+ // This registers your plugin as
172+ registerPlugin('render', 'smiles', smileEmojiPlugin);
173+ ```
174+
175+
176+ ### <a name =" render-plugin-configure " ></a > Render Plugin Examples
177+ Here are links to the built-in __ render plugins__ in Scully:
178+ - [ Route Content Renderer Plugin] ( ../scully/renderPlugins/routeContentRenderer.ts )
179+ - [ Content Folder Plugin] ( ../scully/ )
180+
181+ [ Back to top] ( #plugins )
182+
183+ ---
184+
185+ ## <a name =" file-plugin " ></a > File Handler Plugins
186+
187+
188+ ### <a name =" file-plugin-what-is " ></a > What is a File Handler Plugin?
189+
190+ A __ file handler plugin__ is used by the ` contentFolder ` plugin during the ` render ` process. As the ` contentFolder `
191+ plugin processes the folders for markdown files or whatever they contain, it ends that process by seeing if a
192+ ` fileHandler ` plugin exists for that file extenion type.
193+
194+ Scully comes with two built-in ` fileHandler ` plugins. The [ markdown plugin] ( ../scully/fileHanderPlugins/markdown.ts ) and
195+ the [ asciidoc plugin] ( ../scully/fileHanderPlugins/asciidoc.ts ) . These two plugins are there to handle and process the
196+ content of those types of files as they are read from the file system.
197+
198+ Suppose you wanted to support ` .docx ` files, or ` .csv ` files, or anything else. You would want to add a file handler
199+ for those types of files. The ` contentFolder ` plugin will take care of reading those files from the filesystem, but
200+ what if you wanted to transform them somehow AFTER the ` contentFolder ` plugin reads them. You would need a ` fileHandler `
201+ plugin for this.
202+
203+ ### <a name =" file-plugin-interface " ></a > File Handler Plugin Interface
204+
205+ A __ file handler plugin__ is a function that returns a ` Promise<string> ` . Here is what the interface looks like:
206+ ``` typescript
207+ function exampleFileHandlerPlugin(rawContent : string ) : Promise <string > {
208+ // must return a promise here
209+ }
210+ ```
211+
212+ ### <a name =" file-plugin-how-to " ></a > How To Make A File Handler Plugin
213+
214+ The following is a sample __ file handler plugin__ that handles CSV by wrapping it in a code block. You could of course,
215+ do something much more elaborate like create a table or a grid for this data. Example:
216+
217+ ``` ecmascript 6
218+ function csvFilePlugin(raw) {
219+ return Promise.resolve(`<pre><code>${code}</code></pre>`);
220+ }
221+ // This registers your plugin
222+ registerPlugin('fileHandler', 'csv', { handler: csvFilePlugin});
223+ ```
58224
59- Describe data transform plugins
225+ ### <a name =" file-plugin-configure " ></a > File Handler Plugin Examples
226+ Here are links to the built-in __ render plugins__ in Scully:
227+ - [ asciidoc Plugin] ( ../scully/fileHanderPlugins/asciidoc.ts )
228+ - [ markdown Plugin] ( ../scully/fileHanderPlugins/markdown.ts )
60229
230+ [ Back to top] ( #plugins )
61231
62232[ Full Documentation ➡️] ( scully.md )
0 commit comments