### Install and generate Scully for vanilla NX projects Source: https://scully.io/docs/Reference/schematics/create-scully-files-with-ng-add/ For vanilla NX projects, first install the `@scullyio/init` package, then run the `install` schematic with the project name. ```bash npm install @scullyio/init ``` ```bash nx g @scullyio/init:install -- --project= ``` -------------------------------- ### Install the sitemap plugin with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/sitemap/ Install the `@gammastream/scully-plugin-sitemap` package as a dev dependency. ```bash npm install @gammastream/scully-plugin-sitemap --save-dev ``` -------------------------------- ### Example URL for checking static file Source: https://scully.io/docs/learn/getting-started/tips-for-testing/ When a static file seems incorrect, start the Scully server and visit a route like this to check the rendered content. If the page looks correct but the static file is partial, the issue may be zoneJS idle detection. ```text Copyhttp://localhost:1864/a/path/in/my/app ``` -------------------------------- ### Install with yarn Source: https://scully.io/docs/Reference/plugins/community-plugins/amp-css/ Install the scully-plugin-amp-css package as a dev dependency using yarn. ```bash yarn add scully-plugin-amp-css --dev ``` -------------------------------- ### Install with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/amp-css/ Install the scully-plugin-amp-css package as a dev dependency using npm. ```bash npm install scully-plugin-amp-css --save-dev ``` -------------------------------- ### Install scully-plugin-minify-html with yarn Source: https://scully.io/docs/Reference/plugins/community-plugins/minifyHtml/ Install the plugin using yarn. The html-minifier package is installed automatically. ```bash $ yarn add scully-plugin-minify-html ``` -------------------------------- ### Install scully-plugin-toc with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/toc/ Install the plugin as a dev dependency using npm. ```bash Copynpm i scully-plugin-toc --save-dev ``` -------------------------------- ### Install scully-plugin-meetup with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/meetup/ Install the plugin as a dev dependency using npm. ```bash Copy$ npm install scully-plugin-meetup --save-dev ``` -------------------------------- ### Install PrismJS and generate highlight service Source: https://scully.io/docs/Reference/utilities/prism-js/ Commands to install PrismJS and generate an Angular service for highlighting. ```bash npm i --save prismjs ng g s highlight ``` -------------------------------- ### Install scully-plugin-time-to-read with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/time-to-read/ Install the plugin as a dev dependency using npm. ```bash Copy$ npm install scully-plugin-time-to-read --save-dev ``` -------------------------------- ### Install Playwright plugin package Source: https://scully.io/docs/Reference/routRenders/playwright/ Install the @scullyio/scully-plugin-playwright package using npm. ```bash Copynpm i @scullyio/scully-plugin-playwright ``` -------------------------------- ### Apply styles to app-root-scully Source: https://scully.io/docs/Reference/plugins/built-in-plugins/flashPrevention/ CSS example showing how to update styles to apply to both app-root and app-root-scully, as required for the plugin to work correctly. ```css // BEFORE app-root { ... some styles; } // AFTER app-root, app-root-scully { ... some styles; } ``` -------------------------------- ### Generate a blog post and observe the output Source: https://scully.io/docs/learn/create-a-blog/generate-new-blog-posts/ This example shows the command to create a blog post named 'Angular tutorial'. The output prompts for the target folder (default `blog`) and confirms the creation of `blog/angular-tutorial.md`. ```bash ng generate @scullyio/init:post --name="Angular tutorial" ? What's the target folder for this post? blog ✅️ Blog ./blog/angular-tutorial.md file created CREATE blog/angular-tutorial.md (99 bytes) ``` -------------------------------- ### Example of pre-rendered routes for `/user/:userId` Source: https://scully.io/docs/faq/ Shows how Scully can turn `/user/:userId` into a list of meaningful pre-renderable routes like `/user/1`, `/user/2`, etc. ```text Copy/user/1 /user/2 /user/3 ... /user/100 ``` -------------------------------- ### Install SPS packages Source: https://scully.io/docs/Reference/routRenders/sps/ Install the required packages for the SPS renderer: @angular/platform-server and @scullyio/platform-server. ```bash Copynpm i @angular/platform-server npm i @scullyio/platform-server ``` -------------------------------- ### Example: serve static dist with http-server Source: https://scully.io/docs/faq/ Shows how to serve the generated static site using `http-server` from the `dist/static` directory. This is useful for testing non-generated dynamic routes on a fully featured server. ```bash Copycd dist/static npx http-server ``` -------------------------------- ### Example URL Source: https://scully.io/docs/concepts/unhandled-routes/ Shows a typical application URL that contains an unhandled route path. ```text Copyhttp://localhost:4200/docs/concepts/unhandled-routes ``` -------------------------------- ### Example routes list Source: https://scully.io/docs/Reference/plugins/types/route-process/ A list of example routes that might be configured by a route process plugin. This is used to illustrate the need for removing specific routes. ```text /user/1 /user/2 /user/3 /user/4 /user/5 ``` -------------------------------- ### Install scully-plugin-minify-html with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/minifyHtml/ Install the plugin as a dev dependency using npm. The html-minifier package is installed automatically. ```bash $ npm install scully-plugin-minify-html --save-dev ``` -------------------------------- ### Install with NPM Source: https://scully.io/docs/Reference/plugins/community-plugins/canonical/ Install the scully-plugin-canonical package as a dev dependency using NPM. ```bash npm install scully-plugin-canonical --save-dev ``` -------------------------------- ### Install @notiz/scully-plugin-medium-zoom with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/mediumZoom/ Install the plugin as a dev dependency using npm. Run this command in your project root. ```bash npm install @notiz/scully-plugin-medium-zoom --save-dev ``` -------------------------------- ### Install with Yarn Source: https://scully.io/docs/Reference/plugins/community-plugins/canonical/ Install the scully-plugin-canonical package as a dev dependency using Yarn. ```bash yarn add scully-plugin-canonical --dev ``` -------------------------------- ### Install with yarn Source: https://scully.io/docs/Reference/plugins/community-plugins/disableAngular/ Install the disableAngular plugin using yarn. ```bash yarn add scully-plugin-disable-angular ``` -------------------------------- ### Serve the static site with Scully Source: https://scully.io/docs/learn/create-a-blog/generate-new-blog-posts/ Run `npx scully:serve` to start both the Angular distribution server and the Scully static server. The output shows the URLs for both servers. ```bash npx scully:serve ``` -------------------------------- ### Example output of the markdown schematic Source: https://scully.io/docs/Reference/schematics/create-markdown-files-and-skeleton/ Shows the interactive prompts and the file creation/update output when running the schematic with example answers. The output includes the created files and the updated config. ```bash Copyng g @scullyio/init:markdown ? What name do you want to use for the module? myMarkdown ? What slug do you want for the markdown file? idFile ? Where do you want to store your markdown files? myMarkdownFolder ? Under which route do you want your files to be requested? md ✅️ Update scully.t1.config.ts CREATE src/app/my-markdown/my-markdown-routing.module.ts (439 bytes) CREATE src/app/my-markdown/my-markdown.component.html (153 bytes) CREATE src/app/my-markdown/my-markdown.component.spec.ts (657 bytes) CREATE src/app/my-markdown/my-markdown.component.ts (516 bytes) CREATE src/app/my-markdown/my-markdown.component.css (131 bytes) CREATE src/app/my-markdown/my-markdown.module.ts (424 bytes) UPDATE scully.t1.config.ts (631 bytes) UPDATE src/app/app-routing.module.ts (634 bytes) ✅️ Blog ./my-markdown-folder/2020-09-17-my-markdown.md file created CREATE my-markdown-folder/2020-09-17-my-markdown.md (111 bytes) ``` -------------------------------- ### Full Scully config example with md plugin Source: https://scully.io/docs/Reference/plugins/built-in-plugins/md/ A complete example of a Scully config file that imports Java language support and sets up a content folder route for a blog. ```typescript // scully.your-app.config.ts import { setPluginConfig, ScullyConfig } from '@scullyio/scully'; import 'prismjs/components/prism-java.js'; // example language support export const config: ScullyConfig = { routes: { '/blog/:slug': { type: 'contentFolder', slug: { folder: './blog', }, }, }, }; ``` -------------------------------- ### Install Scully packages with npm Source: https://scully.io/docs/learn/getting-started/manualInstallation/ Use npm to install the required Scully packages: @scullyio/scully and @scullyio/ng-lib. ```bash Copynpm i @scullyio/scully @scullyio/ng-lib ``` -------------------------------- ### Install with Yarn Source: https://scully.io/docs/Reference/plugins/community-plugins/page-title/ Install the scully-plugin-page-title package as a dev dependency using Yarn. ```bash yarn add scully-plugin-page-title --dev ``` -------------------------------- ### Install with NPM Source: https://scully.io/docs/Reference/plugins/community-plugins/page-title/ Install the scully-plugin-page-title package as a dev dependency using NPM. ```bash npm install scully-plugin-page-title --save-dev ``` -------------------------------- ### Install critical-css plugin with npm Source: https://scully.io/docs/Reference/plugins/built-in-plugins/criticalcss/ Install the @scullyio/scully-plugin-critical-css package as a dev dependency. ```bash Copynpm install -D @scullyio/scully-plugin-critical-css ``` -------------------------------- ### Install scully-plugin-fouc with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/fouc/ Install the plugin as a dev dependency using npm. ```bash Copy$ npm install @notiz/scully-plugin-fouc --save-dev ``` -------------------------------- ### Install scully-plugin-lazy-images with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/lazyImages/ Install the plugin as a dev dependency using npm. ```bash npm install @notiz/scully-plugin-lazy-images --save-dev ``` -------------------------------- ### Dockerfile base configuration for Scully with puppeteer Source: https://scully.io/docs/faq/ Base Docker configuration that installs Chromium and sets PUPPETEER_SKIP_CHROMIUM_DOWNLOAD to true. This is a starting point for running Scully in Docker or CI/CD environments. ```docker CopyFROM node:12-alpine RUN apk add --no-cache \ chromium \ ca-certificates ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true ``` -------------------------------- ### Install Scully packages with yarn Source: https://scully.io/docs/learn/getting-started/manualInstallation/ Use yarn to install the required Scully packages: @scullyio/scully and @scullyio/ng-lib. ```bash Copyyarn add @scullyio/scully @scullyio/ng-lib ``` -------------------------------- ### Install Chrome for WSL Source: https://scully.io/docs/learn/getting-started/installation/ WSL does not include Chrome, so Puppeteer needs it installed. Download and install the stable Chrome .deb package. ```bash Copywget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo apt install ./google-chrome-stable_current_amd64.deb ``` -------------------------------- ### Install http404 plugin with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/http404/ Install the plugin as a dev dependency using npm. Version 1.0.0 introduces breaking changes in registration and configuration. ```bash npm install @gammastream/scully-plugin-http404 --save-dev ``` -------------------------------- ### Launch Scully test server with npx scully serve Source: https://scully.io/docs/learn/getting-started/serving/ Run this command to start Scully's test server after building your app. It launches two servers: one hosting the results of ng build and another hosting the Scully build results, allowing you to test both versions. ```bash Copynpx scully serve ``` -------------------------------- ### Blog post frontmatter example Source: https://scully.io/docs/learn/create-a-blog/use-blog-post-data-in-template/ Example of frontmatter in a .md blog post file that defines metadata properties accessible via ScullyRoutesService.available$. ```markdown --- title: blog title description: blog description published: true arbitraryValue: single value arbitraryArray: [first item, second item] --- ``` -------------------------------- ### Install @notiz/scully-plugin-rss with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/rss/ Install the RSS Feed plugin as a dev dependency using npm. ```bash Copynpm install @notiz/scully-plugin-rss --save-dev ``` -------------------------------- ### Install flash-prevention plugin Source: https://scully.io/docs/Reference/plugins/built-in-plugins/flashPrevention/ Command to install the flash-prevention plugin as a dev dependency. ```bash npm install -D @scullyio/scully-plugin-flash-prevention ``` -------------------------------- ### Install @gammastream/scully-plugin-regex with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/regex/ Install the plugin as a dev dependency using npm. This is required before configuring the plugin. ```bash Copy$ npm install @gammastream/scully-plugin-regex --save-dev ``` -------------------------------- ### Full Scully config with puppeteer launch options for GCE Source: https://scully.io/docs/faq/ Complete ScullyConfig example with puppeteerLaunchOptions including executablePath and a list of Chromium flags. Reported to help with GCE timeout failures. ```typescript Copyexport const config: ScullyConfig = { projectRoot: './pathToRoot', projectName: 'nameOfProject', outDir: './dist/static', routes: { /** your route config **/ }, defaultPostRenderers, puppeteerLaunchOptions: { executablePath: '/usr/bin/chromium-browser', args: [ '--no-sandbox', '--disable-setuid--sandbox', '--headless', '--disable-gpu', '--disable-dev-shm-usage', '--no-default-browser-check', '--no-first-run', '--disable-default-apps', '--disable-popup-blocking', '--disable-translate', '--disable-background-timer-throttling', '--disable-renderer-backgrounding', '--disable-device-discovery-notifications', '--disable-web-security', ], }, }; ``` -------------------------------- ### scullyStats.json example Source: https://scully.io/docs/Reference/command-line-options/ Example layout of the JSON file generated by the `--stats` flag. ```json { "numberOfRoutes": 51, "generatingTime": 55.63, "routesPerSecond": 0.92, "findingRoutesAngular": 2.71838, "routeDiscovery": 0.00026, "renderingPages": 52.21755 } ``` -------------------------------- ### npx scully serve Source: https://scully.io/docs/Reference/command-line-options/ Starts the Scully server. This process does not build the project; it only serves the Angular build files and Scully static files. ```bash npx scully serve ``` -------------------------------- ### Example HTML content with TOC placeholder Source: https://scully.io/docs/Reference/plugins/community-plugins/toc/ Example of a blog post HTML with a div with id 'toc' where the TOC will be inserted. The headings h2 and h3 will be used to generate the TOC. ```html Copy# my blog post

Table of contents

## heading 1 ### subheading 1 ## heading 2 ### subheading 2 ``` -------------------------------- ### Install with npm Source: https://scully.io/docs/Reference/plugins/community-plugins/disableAngular/ Install the disableAngular plugin as a dev dependency using npm. ```bash npm install scully-plugin-disable-angular --save-dev ``` -------------------------------- ### plugins.ts example Source: https://scully.io/docs/learn/getting-started/manualInstallation/ Create a plugins.ts file inside the scully/plugins directory with this content to register a custom render plugin. ```typescript Copyimport { registerPlugin, getPluginConfig } from '@scullyio/scully'; export const myPlugin = 'myPlugin'; const myFunctionPlugin = async (html: string): Promise => { return html; }; const validator = async () => []; registerPlugin('render', myPlugin, myFunctionPlugin, validator); ``` -------------------------------- ### Scully blog generation output Source: https://scully.io/docs/Reference/schematics/create-blog-config/ Example output from running the blog schematic, showing updated and created files, including the blog markdown file. ```bash ng g @scullyio/init:blog ✅️ Update scully.t1.config.ts UPDATE scully.t1.config.ts (511 bytes) UPDATE src/app/app-routing.module.ts (524 bytes) CREATE src/app/blog/blog-routing.module.ts (406 bytes) CREATE src/app/blog/blog.component.html (153 bytes) CREATE src/app/blog/blog.component.spec.ts (614 bytes) CREATE src/app/blog/blog.component.ts (489 bytes) CREATE src/app/blog/blog.component.css (131 bytes) CREATE src/app/blog/blog.module.ts (380 bytes) ✅️ Blog ./blog/2020-09-17-blog.md file created CREATE blog/2020-09-17-blog.md (97 bytes) ``` -------------------------------- ### Install events-polyfill for Internet Explorer 10+ Source: https://scully.io/docs/Reference/legacy-support/polyfills/ Install the events-polyfill package to support Internet Explorer 10+ in Scully V1. This polyfill is required because Scully uses the Event constructor. ```bash npm install events-polyfill ``` -------------------------------- ### Install Scully with ng add Source: https://scully.io/docs/learn/getting-started/installation/ Run this command to add Scully to an Angular project. It runs the init schematic and creates the Scully config file. ```bash Copyng add @scullyio/init ``` -------------------------------- ### Register a beforeAll Plugin with registerPlugin Source: https://scully.io/docs/Reference/plugins/types/beforeAll/ Example of registering a custom beforeAll plugin using the registerPlugin function from @scullyio/scully. The plugin function can perform tasks like copying files before the Scully run. ```typescript Copyconst { registerPlugin } = require('@scullyio/scully'); function customCopyPlugin() { // Do something to your Scully site /** copy some extra files into my dist folder */ } const validator = async () => []; registerPlugin('beforeAll', 'copy in my custom files', customCopyPlugin); ``` -------------------------------- ### Install version 8 dependencies Source: https://scully.io/docs/Reference/legacy-support/angular-v8/ Installs dependencies for Angular version 8 using npm. ```bash npm i ``` -------------------------------- ### Build and run Scully Source: https://scully.io/docs/Reference/plugins/community-plugins/minifyHtml/ Build the app and then run the Scully command to prerender pages with the minifyHtml plugin. ```bash npm run build --prod npx scully ``` -------------------------------- ### Example usage of findPlugin Source: https://scully.io/docs/Reference/scully-api/findPlugin/ Demonstrates two ways to use findPlugin: passing only the plugin name, or passing the plugin type and name. The returned plugin instance is invoked with the required parameters (routes for a router plugin, htmlString and handledRouteData for a render plugin). ```typescript Copyconst routerPlugin = findPlugin('myRouterPlugin'); const pluginResult = await routerPlugin(routes); // OR const renderPlugin = findPlugin(RenderPlugin, 'myRenderPlugin'); const pluginResult = await renderPlugin(htmlString, handledRouteData); ``` -------------------------------- ### CSV fileHandler plugin example with registration Source: https://scully.io/docs/Reference/plugins/types/fileHandler/ Example plugin that wraps CSV content in a code block. Must be registered with registerPlugin and exported via module.exports. ```typescript Copyfunction csvFilePlugin(raw) { return Promise.resolve(`
${code}
`); } // DO NOT FORGET TO REGISTER THE PLUGIN registerPlugin('fileHandler', 'csv', { handler: csvFilePlugin }); module.exports.csvFilePlugin = csvFilePlugin; ``` -------------------------------- ### Example router plugin function signature Source: https://scully.io/docs/Reference/plugins/types/router/ Shows the required structure of a router plugin function: it receives a route string and config, and must return a Promise. ```typescript Copyfunction exampleRouterPlugin( route: string, config: any ): Promise { // Must return a promise } ``` -------------------------------- ### Configuration with defaultPostRenderers and postRenderers Source: https://scully.io/docs/Reference/plugins/types/route-process/ Shows how to configure routes with defaultPostRenderers and postRenderers. The defaultPostRenderers array is used as a base, and postRenderers can add to or replace it. The example demonstrates a normal route, a route that adds to the default, and a route that removes the default. ```typescript Copyconst defaultPostRenderers = ['seoHrefOptimise']; const sampleConf: ScullyConfig = { defaultPostRenderers, routes: { /** gets the default postrenderes */ normalRoute: { type: 'default', }, /** adds to the default postrenderes */ someRoute: { type: 'default', postRenderers: [...defaultPostRenderers, 'myAddition'], }, /** removes the default postrenderes */ someOtherRoute: { type: 'default', postRenderers: ['unique'], }, }, }; ``` -------------------------------- ### extraRoutes example Source: https://scully.io/docs/Reference/config/ Example of the extraRoutes property, which allows adding an array of unhandled routes. These routes can exist in AngularJS, React, or any other framework. ```typescript CopyextraRoutes: [ '/foo/:id', new Promise('/bar/:barId'), new Promise(['/foo/:fooId', '/bar/:id']), ]; ``` -------------------------------- ### Import Prism language support Source: https://scully.io/docs/Reference/plugins/built-in-plugins/md/ Import additional Prism language components in your Scully config file. This example imports Java support. ```typescript /** this line goes into your scully..config.ts */ import 'prismjs/components/prism-java.js'; ``` -------------------------------- ### Build and run Scully Source: https://scully.io/docs/Reference/plugins/community-plugins/regex/ Build the app and run Scully to generate the static site with the regex plugin applied. ```bash Copynpm run build npx scully ``` -------------------------------- ### Build and run Scully with stats-json Source: https://scully.io/docs/Reference/plugins/community-plugins/disableAngular/ Build the app with --stats-json flag and run Scully to generate the static site. ```bash npm run build -- --prod --stats-json npx scully ``` -------------------------------- ### Validator example using yellow from @scullyio/scully Source: https://scully.io/docs/Reference/scully-api/registerPlugin/ Example of a validator function that checks if numberOfPages is a number and returns an array of errors, using the yellow color from Scully. ```typescript Copyimport { yellow } from '@scullyio/scully'; // Omitted code ... const validator = async (options) => { const errors = []; if (options.numberOfPages && typeof options.numberOfPages !== 'number') { errors.push( `my-custom-plugin numberOfPages should be a number, not a ${yellow( typeof options.numberOfPages )}` ); } return errors; }; ``` -------------------------------- ### Example route process plugin function Source: https://scully.io/docs/Reference/plugins/types/route-process/ Shows the expected signature for a route process plugin function. It receives an array of HandledRoute and returns a Promise of HandledRoute array. The function should process each route and return them, which are then added to scully-routes.json. ```typescript Copyfunction exampleRouterPlugin(routes: HandledRoute[]): Promise {} ``` -------------------------------- ### Implementing a router plugin (userIdPlugin) Source: https://scully.io/docs/Reference/plugins/types/router/ TypeScript example of a router plugin that returns five HandledRoutes for the /user/:userId route. It uses registerPlugin with the 'router' type and 'userIds' name, and includes a validator function. ```typescript import { HandledRoute, registerPlugin } from "@scullyio/scully" function userIdPlugin(route: string, config = {}): Promise { return Promise.resolve([ { route: '/user/1' }, { route: '/user/2' }, { route: '/user/3' }, { route: '/user/4' }, { route: '/user/5' }, ]); } const validator = async (conf) => []; registerPlugin('router', 'userIds', userIdPlugin, validator); ``` -------------------------------- ### Output after adding blog support Source: https://scully.io/docs/learn/create-a-blog/add-blog-support/ Expected output after running the blog schematic. It updates configuration and creates a sample markdown file. ```bash ✅️ Update scully.{{yourApp}}.config.js UPDATE scully.{{yourApp}}.config.js (653 bytes) UPDATE src/app/app-routing.module.ts (726 bytes) UPDATE src/app/blog/blog-routing.module.ts (429 bytes) UPDATE src/app/blog/blog.component.css (157 bytes) UPDATE src/app/blog/blog.component.html (160 bytes) UPDATE src/app/blog/blog.component.spec.ts (639 bytes) UPDATE src/app/blog/blog.component.ts (508 bytes) UPDATE src/app/blog/blog.module.ts (391 bytes) ✅️ Blog ./mdblog/2020-03-24-blog.md file created CREATE mdblog/2020-03-24-blog.md (95 bytes) ``` -------------------------------- ### Example of a handled route array Source: https://scully.io/docs/concepts/handled-routes/ Shows the output of a router plugin: an array of HandledRoute objects with route and type properties. The route is a complete path like '/user/1' and the type is 'json'. ```typescript const handledRoutes:HandledRoute[] = [ { route: '/user/1' type: 'json' }, { route: '/user/2' type: 'json' }, ... { route: '/user/10' type: 'json' }, ] ``` -------------------------------- ### Full json plugin options example in scully.config.ts Source: https://scully.io/docs/Reference/plugins/built-in-plugins/json/ Shows all configurable options for the json plugin: postRenderers, url, property, headers (including expectedContentType), and resultsHandler. The resultsHandler maps the API response to an array of route parameters. ```typescript // scully.config.ts export const config: ScullyConfig = { routes: { '/users/:userId': { type: 'json', /** * postRenderers: postRenderers[] * * This options allows you to configure postRenderers for this route returned * by this `/users/:userId` plugin. */ postRenderers: [], userId: { /** * url: string * * An API that returns a response containing the data (preferribly an array) * needed for all `userId`s in the system. */ url: 'https://my-api.com/users', /** * property: string * * If the `url` returns an array of objects, use the `property` to provide the * name of the property that can be used to pluck the `userId` from each item. * If the APi returns a list of items using the `id` property for the `userId`, * the following config would pluck the `id` property off of each user object. */ property: 'id', /** * headers: {[key:string]:any} * * If the `url` API requires specific headers, you can provide those here. The * header name is the key, and the header value is the value. */ headers: { /** * expectedContentType: string * * By default plugin expects `application/json` Content-Type in response headers. * If the API returns different type of content use the `expectedContentType` to specify * different type. Error will be thrown if content types do not match. */ expectedContentType: 'application/vnd.api+json', 'API-KEY': '0123456789', }, /** * resultsHandler: (response: any) => any[] * * If the `url` returns an object, use the `resultsHandler` to map that object * into an array of objects/ids. * * In the following example, the server returned an object where the users were * nested inside of the `response.data` property. So the resultsHandler returns * `response.data.users`. */ resultsHandler: (response) => response.data.users, }, }, }, }; ``` -------------------------------- ### Generate blog support with @scullyio/init:blog Source: https://scully.io/docs/learn/create-a-blog/add-blog-support/ Run this command to add blog support to an Angular application. It adds the blog module's routes and creates a `./blog` folder for markdown files. ```bash ng generate @scullyio/init:blog ``` -------------------------------- ### Generate lazy-loaded home route Source: https://scully.io/docs/learn/getting-started/requirements/ Use this Angular CLI command to add a lazy-loaded route named 'home' to your app. This is an example of setting up a route for Scully to process. ```bash ng generate module home --route home --module app ``` -------------------------------- ### Angular route configuration with parameterized routes Source: https://scully.io/docs/concepts/unhandled-routes/ Example of Angular route configuration with a lazy-loaded module and nested parameterized routes. Scully traverses these to generate unhandled routes. ```typescript Copy/** in app-router **/ const routes: Routes = [ { path: 'user', loadChildren: () => import('./user/user.module').then((m) => m.UserModule), }, ]; /** in user-routing.module **/ const routes: Routes = [ { path: '', component: UsersComponent }, { path: ':userId', component: UserComponent, children: [ { path: '', component: PostsComponent, pathMatch: 'full' }, { path: 'friend/:friendCode', component: UserComponent }, { path: 'post/:postId', component: PostComponent }, ], }, ]; ``` -------------------------------- ### npx scully --baseFilter="/someRoute*" Source: https://scully.io/docs/Reference/command-line-options/ Alias `--bf`. Enables Scully to start rendering specific routes. You can provide a wildcard string separated by commas to filter unhandled routes. ```bash npx scully --baseFilter="/someRoute*" ``` -------------------------------- ### Async function replacing strings in HTML Source: https://scully.io/docs/Reference/plugins/custom-plugins/create-a-plugin-function/ Example of a custom plugin as an async function that replaces strings in HTML. It uses a replaceStrings array and the forEach method to perform replacements. ```typescript Copyasync function replaceThings(html: string, route: handledRoute) { const replaceStrings = [[':)', '☺']]; replaceString.forEach( (find, replace) => (html = html.split(find).join(replace)) ); return html; } ``` -------------------------------- ### Generate blog support with custom folder using @scullyio/init:markdown Source: https://scully.io/docs/learn/create-a-blog/add-blog-support/ Use this command to specify a different folder name for markdown files. You will be prompted for module name, slug, source directory, and route. ```bash ng generate @scullyio/init:markdown ``` -------------------------------- ### Build and run Scully with SPS Source: https://scully.io/docs/Reference/routRenders/sps/ Build your app first with npx ng build, then run Scully with npx scully. The renderer creates ./scully/tsconfig..json and compiles to ./scully/runtime. ```bash Copy # first build your app, as Scully still needs the static artifacts npx ng build # run Scully npx scully ``` -------------------------------- ### Confirm blog post file creation Source: https://scully.io/docs/learn/create-a-blog/generate-new-blog-posts/ This message confirms that the file `angular-tutorial.md` was created in the `blog/` directory. ```bash CREATE blog/angular-tutorial.md ``` -------------------------------- ### Serve Scully static site with npx scully:serve Source: https://scully.io/docs/learn/create-a-blog/generate-new-blog-posts/ Run this command to serve the static site locally. The blog post will be available at http://localhost:1668/blog/angular-tutorial. ```bash npx scully:serve ``` -------------------------------- ### npx scully --tds Source: https://scully.io/docs/Reference/command-line-options/ Launches the Test Data Server. Only helpful for demos. ```bash npx scully --tds ``` -------------------------------- ### Build and run Scully with Playwright renderer Source: https://scully.io/docs/Reference/routRenders/playwright/ First build your app with ng build, then run npx scully. The Playwright renderer will render routes and output a static site. ```bash Copy # first build your app, as Scully still needs the static artifacts npx ng build # run Scully npx scully ``` -------------------------------- ### Generate a new blog post with default options Source: https://scully.io/docs/learn/create-a-blog/generate-new-blog-posts/ Run this command to create a new blog post. The `name` option sets the post title; if omitted, the default is 'blog-X'. The post is created in the `blog/` directory by default. ```bash ng generate @scullyio/init:post --name="This is my post" ``` -------------------------------- ### Generate home module with route Source: https://scully.io/docs/learn/create-a-blog/add-blog-support/ Creates a home module with a route and registers it in the app routing module. Scully depends on this route entry point. ```bash ng generate module home --route=home --module=app-routing ``` -------------------------------- ### Configure criticalCSS settings with setPluginConfig Source: https://scully.io/docs/Reference/plugins/built-in-plugins/criticalcss/ Use setPluginConfig to configure the criticalCSS plugin, for example to disable inlineImages. ```typescript CopysetPluginConfig(criticalCSS, { inlineImages: false, }); ``` -------------------------------- ### Build and run Scully Source: https://scully.io/docs/Reference/plugins/community-plugins/http404/ Commands to build the Angular app and run Scully to generate the static site, including the 404 page. ```bash npm run build npx scully ``` -------------------------------- ### Remove version 9 node_modules Source: https://scully.io/docs/Reference/legacy-support/angular-v8/ Removes the node_modules directory to clear version 9 dependencies before installing version 8. ```bash rm -fr node_modules ``` -------------------------------- ### Generate blog support with flags to avoid prompts Source: https://scully.io/docs/learn/create-a-blog/add-blog-support/ Run the markdown schematic with flags to skip interactive prompts. Specify name, slug, source directory, and route directly. ```bash ng generate @scullyio/init:markdown --name="blog" --slug="title" --source-dir="mdblog" --route="blog" ``` -------------------------------- ### Using extraRoutes with an async function Source: https://scully.io/docs/concepts/unhandled-routes/ Example of using an async function to fetch routes from an external API and pass them to `extraRoutes`. ```typescript Copyconst config:ScullyConfig = { ... extraRoutes: httpGetJson('http://web.archive.org/cdx/search/cdx?url=scully.io*&output=json').then(cleanup), ... } ``` -------------------------------- ### Build the Angular v8 library Source: https://scully.io/docs/Reference/legacy-support/angular-v8/ Builds the @scullyio/ng-lib-v8 library using Angular CLI. ```bash ng build @scullyio/ng-lib-v8 ``` -------------------------------- ### registerPlugin('postProcessByHtml', 'smiles', smileEmojiPlugin, validator) Source: https://scully.io/docs/Reference/plugins/types/postProcessByHtml/ Example of registering a postProcessByHtml plugin that replaces all instances of ':)' with a smiley emoji. The plugin is registered with the name 'smiles'. ```APIDOC ## registerPlugin('postProcessByHtml', 'smiles', smileEmojiPlugin, validator) ### Description Registers a postProcessByHtml plugin named 'smiles' that replaces all occurrences of ':)' with the 😊 emoji in the HTML. ### Method registerPlugin ### Parameters - **type** (string) - Required - The plugin type, must be 'postProcessByHtml'. - **name** (string) - Required - The plugin name, 'smiles'. - **plugin** (function) - Required - The plugin function that takes (html, route) and returns a Promise. - **validator** (function) - Required - An async function that validates the plugin configuration, returns an array of errors. ### Plugin Function Example ```typescript function smileEmojiPlugin(html, route) { return Promise.resolve(html.replace(/\:\)/g, '😊')); } ``` ### Registration Example ```typescript const { registerPlugin } = require('@scullyio/scully'); function smileEmojiPlugin(html, route) { return Promise.resolve(html.replace(/\:\)/g, '😊')); } // DON NOT FORGET REGISTER THE PLUGIN const validator = async (conf) => []; registerPlugin('postProcessByHtml', 'smiles', smileEmojiPlugin, validator); module.exports.smileEmojiPlugin = smileEmojiPlugin; ``` ``` -------------------------------- ### Add Scully and generate static site Source: https://scully.io/docs/learn/introduction/ Run these commands in order to add Scully to an Angular project, build the production bundle, and generate the static site with Scully. ```bash ng add @scullyio/init ng build --prod npx scully ``` -------------------------------- ### Create app.sps.module.ts Source: https://scully.io/docs/Reference/routRenders/sps/ Create a module with a default export that imports BrowserModule.withServerTransition, AppModule, and ScullyPlatformServerModule. Enable production mode. Ensure the default export and bootstrap AppComponent are present. ```ts Copyimport { enableProdMode, NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { AppModule } from './app.module'; import { ScullyPlatformServerModule } from '@scullyio/platform-server' import { BrowserModule } from '@angular/platform-browser'; /** * the platform server should be running in production mode. */ enableProdMode(); @NgModule({ imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), AppModule, ScullyPlatformServerModule, ], providers: [], bootstrap: [AppComponent], }) export default class AppSPSModule {} ``` -------------------------------- ### registerPlugin('postProcessByHtml', 'defaultTitle', defaultTitlePlugin, validator) Source: https://scully.io/docs/Reference/plugins/types/postProcessByHtml/ Example of registering a postProcessByHtml plugin that adds a default title to the HTML if none is present. The plugin is registered with the name 'defaultTitle'. ```APIDOC ## registerPlugin('postProcessByHtml', 'defaultTitle', defaultTitlePlugin, validator) ### Description Registers a postProcessByHtml plugin named 'defaultTitle' that adds a default title to the HTML if no title tag is found. ### Method registerPlugin ### Parameters - **type** (string) - Required - The plugin type, must be 'postProcessByHtml'. - **name** (string) - Required - The plugin name, 'defaultTitle'. - **plugin** (function) - Required - The plugin function that takes (html, route) and returns a Promise. - **validator** (function) - Required - An async function that validates the plugin configuration, returns an array of errors. ### Plugin Function Example ```typescript function defaultTitlePlugin(html, route) { // If no title in the document if (html.indexOf('The Truth Is Out There!`; return Promise.resolve(`${begin}${defaultTitle}${splitter}${end}`); } return Promise.resolve(html); } ``` ### Registration Example ```typescript const { registerPlugin } = require('@scullyio/scully'); function defaultTitlePlugin(html, route) { // If no title in the document if (html.indexOf('The Truth Is Out There!`; return Promise.resolve(`${begin}${defaultTitle}${splitter}${end}`); } return Promise.resolve(html); } // DON NOT FORGET REGISTER THE PLUGIN const validator = async (conf) => []; registerPlugin( 'postProcessByHtml', 'defaultTitle', defaultTitlePlugin, validator ); module.exports.defaultTitlePlugin = defaultTitlePlugin; ``` ``` -------------------------------- ### Generate Scully static site with npx scully Source: https://scully.io/docs/learn/create-a-blog/generate-new-blog-posts/ Run this command to generate the static site. It will create a route based on the markdown filename by default. ```bash npx scully ``` -------------------------------- ### httpGetJson Source: https://scully.io/docs/Reference/scully-api/utils/ Takes a URL and returns a promise that resolves to the JSON object returned by the URL. The URL must respond to a GET request with a JSON object and a Content-Type: application/json header. ```APIDOC ## httpGetJson ### Description Takes a URL and returns a promise that resolves into the object representing the JSON returned by the URL. The URL has to respond to a GET request with a JSON object and a `Content-Type: application/json` header. ### Usage ```typescript httpGetJson(url).then((response) => console.log(response)); ``` Or in an async function: ```typescript const response = await httpGetJson(url); ``` ### Parameters - `url` (string) - Required - The URL to fetch JSON from. ### Returns A promise that resolves to the JSON object from the URL. ### Example ```typescript import { HandledRoute, httpGetJson, registerPlugin, routeSplit, } from '@scullyio/scully'; registerPlugin('router', 'mySample', async (route: string, config) => { const myData = await httpGetJson(config.url); const { createPath } = routeSplit(route); const myRoutes: HandledRoute[] = myData.map((item) => ({ route: createPath(item.id), })); return myRoutes; }); ``` Then on your config do something like: ```typescript export const config: ScullyConfig = { routes: { '/fromData/:id': { type: 'mySample', url: 'http://localhost:4200/assets/data.json', }, }, }; ``` ``` -------------------------------- ### Prompts for @scullyio/init:markdown Source: https://scully.io/docs/learn/create-a-blog/add-blog-support/ Shows the interactive prompts when running the markdown schematic without flags. Answers define the module name, slug, source directory, and route. ```bash ? What name do you want to use for the module? blog ? What slug do you want for the markdown file? title ? Where do you want to store your markdown files? mdblog ? Under which route do you want your files to be requested? blog ``` -------------------------------- ### Prioritize package.json with --pjFirst Source: https://scully.io/docs/Reference/command-line-options/ In a mixed mono-repo, use --pjFirst to look for package.json first instead of angular.json to find the project root. ```bash Copynpx scully --pjFirst ``` -------------------------------- ### Configure custom minify options with setPluginConfig Source: https://scully.io/docs/Reference/plugins/community-plugins/minifyHtml/ Use setPluginConfig to override the default minify options. The example shows setting removeComments to false. The plugin can be configured with or without the 'render' argument. ```javascript const { RouteTypes, setPluginConfig } = require('@scullyio/scully'); const { MinifyHtml, MinifyHtmlOptions } = require('scully-plugin-minify-html'); const postRenderers = [MinifyHtml]; const minifyHtmlOptions: MinifyHtmlOptions = { minifyOptions: { removeComments: false, }, }; setPluginConfig(MinifyHtml, 'render', minifyHtmlOptions); // or // setPluginConfig(MinifyHtml, minifyHtmlOptions); exports.config = { projectRoot: './src/app', defaultPostRenderers: postRenderers, routes: { '/blog/:slug': { type: RouteTypes.contentFolder, slug: { folder: './blog', }, postRenderers: postRenderers, }, }, }; ``` -------------------------------- ### Trigger fireManualMyAppReadyEvent in component Source: https://scully.io/docs/Reference/ngLib/idle-monitor-service/ Example component that uses IdleMonitorService to manually trigger the ready event after a delay. The component updates its text after 3 seconds and fires the event after 3.25 seconds. ```typescript export class ManualIdleComponent implements OnInit { text = 'this text is displayed by automated detection'; constructor(private ims: IdleMonitorService) {} ngOnInit(): void { setTimeout(() => (this.text = '__ManualIdle__'), 3 * 1000); setTimeout(() => this.ims.fireManualMyAppReadyEvent(), 3.25 * 1000); } } ``` -------------------------------- ### npx scully serve/watch --ssl --ssl-key=./url/to/file Source: https://scully.io/docs/Reference/command-line-options/ Adds a URL to an SSL key file for a server with SSL. ```bash npx scully serve/watch --ssl --ssl-key=./url/to/file ``` -------------------------------- ### Configure localLinksOnly on scully-content Source: https://scully.io/docs/Reference/ngLib/scully-content-component/ Enable scoping of router link upgrade behavior to blog content instead of the whole document. Default is false. Two equivalent syntaxes are shown. ```html ``` -------------------------------- ### npx scully serve/watch --ssl Source: https://scully.io/docs/Reference/command-line-options/ Runs the Scully server with SSL. ```bash npx scully serve/watch --ssl ``` -------------------------------- ### ScullyLibConfig interface Source: https://scully.io/docs/learn/getting-started/manualInstallation/ Optional configuration interface for ScullyLibModule using the forRoot method. Defaults work without passing any configuration. ```ts Copyexport interface ScullyLibConfig { useTransferState?: boolean; alwaysMonitor?: boolean; manualIdle?: boolean; baseURIForScullyContent?: string; } ``` -------------------------------- ### npx scully serve/watch --open Source: https://scully.io/docs/Reference/command-line-options/ Alias `--o`. Opens the default browser and renders the dist folder generated by Scully. ```bash npx scully serve/watch --open ``` -------------------------------- ### Error message when scully cannot find local copy Source: https://scully.io/docs/faq/ This error message appears when you start scully outside of a scully project folder or when using PowerShell with mixed case path-names. It indicates that the local copy of scully cannot be found. ```text -------------------------------------------------------------------------- you started scully outside of a scully project-folder, or didn't install packages in this folder. We can't find your local copy to start. This can also happen on windows with PowerShell and mixed case path-names -------------------------------------------------------------------------- ``` -------------------------------- ### Configure ScullyLibModule with manualIdle Source: https://scully.io/docs/Reference/ngLib/idle-monitor-service/ Disables Scully's ready mechanism and enables a custom one by setting manualIdle: true in the forRoot config. This causes Scully to fall back to a 25-second timeout on every page rendered. ```typescript ScullyLibModule.forRoot({ useTransferState: true, alwaysMonitor: false, manualIdle: true, }); ``` -------------------------------- ### Disable project folder check with --disableProjectFolderCheck Source: https://scully.io/docs/Reference/command-line-options/ Disables checking if Scully was launched from the project folder. Allows installing Scully as a symlinked dependency (e.g., pnpm or npm link). Use with caution as it may cause errors in certain environments. ```bash Copynpx scully --disableProjectFolderCheck ``` -------------------------------- ### httpGetJson sample plugin Source: https://scully.io/docs/Reference/scully-api/utils/ Demonstrates using httpGetJson to fetch data from a config URL and routeSplit to create routes. The plugin expects the URL to return JSON. ```typescript Copyimport { HandledRoute httpGetJson, registerPlugin, routeSplit} = from '@scullyio/scully'; registerPlugin('router', 'mySample', async(route: string, config) => { const myData = await httpGetJson(config.url); const { createPath } = routeSplit(route); const myRoutes: HandledRoute[] = myData.map((item) => ({ route: createPath(item.id) })); return myRoutes; }) ``` -------------------------------- ### Publish the library Source: https://scully.io/docs/Reference/legacy-support/angular-v8/ Changes to the dist directory and publishes the library. ```bash cd ./dist/scullyio/ng-lib-v8 ``` -------------------------------- ### Run Scully with npx scully Source: https://scully.io/docs/learn/getting-started/building/ After building the Angular project, run this command to generate the pre-rendered static site. The output is placed in the ./dist/static folder. ```bash npx scully ```