Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 99 additions & 4 deletions libs/scully-plugin-flash-prevention/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,102 @@
# scully-plugin-flash-prevention
# ScullyPluginFlashPrevention

This library was generated with [Nx](https://nx.dev).
The `scully-plugin-flash-prevention` is a postRenderer that helps you hide any flashes that your
app may be experiencing once you add Scully to your project.

## Running unit tests
After adding Scully, your app will appear instantly because the pre-rendered HTML and CSS is
immediately available. After appearing instantly, the JavaScript and CSS files will download and
then your Angular app will bootstrap (init). When it bootstraps, the pre-rendered version may
disappear for a moment, and then once the app is ready, the view will re-appear. This
disappearing-then-appearing is very normal for apps that are pre-rendered on a server. This
project is to prevent that.

Run `ng test scully-plugin-flash-prevention` to execute the unit tests via [Jest](https://jestjs.io).
This project shows the pre-rendered copy of your app until your app is fully render and the
flash is over. It then shows your app and deletes the copy.

### How it works

Before this plugin, you app would pre-render and then save to file, like this:

```html
<app-root _nghost-abc="" ng-version="9.0.1" class="my-class">
// The entire content of your app here
</app-root>
```

After this plugin, you will see the following in your pre-rendered template:

```html
<app-root class="my-class"></app-root>
<app-root-scully _nghost-abc="" ng-version="9.0.1" class="my-class">
// The entire content of your app here
</app-root-scully>
```

This `app-root-scully` will be the pre-rendered copy of your app. Prior to your app being
rendered fully, `app-root` will be hidden and `app-root-scully` will be displayed. Once your
app has fully bootstrapped, `app-root-scully` will be hidden and then 100ms later removed
from the DOM. The mechanism that shows and hides these two is CSS. There is some CSS added
during the Scully build that looks like the following:

```css
body:not(.loaded) app-root {
display: none;
}
body.loaded app-root-scully {
display: inherit;
}
```

Once the app has been fully loaded, the `loaded` class is added to the `<body>` tag.

And that's how it all works!!!

## Getting Started

**1 -** Install the package: `npm install -D scully-plugin-flash-prevention`

**2 -** Add the postRenderer to your `scully.config`:

```javascript
// Add this line to your imports
const { getFlashPreventionPlugin } = require('scully-plugin-flash-prevention');

// Add the following to your `scully.config.postRenderers`
exports.config = {
...
postRenderers : [getFlashPreventionPlugin({appRootSelector: 'custom-app-root'})],
...
}
```

You only need to pass the `{appRootSelector: 'custom-app-root'}` if your app has a selector other
than `app-root`. It is defaulted to `app-root`.

**3 -** Update `app.module` to include `alwaysMonitor` in the `ScullyLibModule.forRoot` call.

```typescript
ScullyLibModule.forRoot({
useTransferState: true,
alwaysMonitor: true, <-- Add this line to your `app.module.ts`
});
```

**4 -** Apply any styles from `app-root` to `app-root-scully` as well. Any styles that are in your
`app.component.(css|scss|less)` need to be applied to the copy of your app that was made. This means
that you need to possibly move any styles that apply to the `app-root` specifically, and put them
in a location where you can also make those styles apply to `app-root-scully` as well. See here:

```css
// BEFORE
app-root {
... some styles;
}

// AFTER
app-root,
app-root-scully {
... some styles;
}
```

That's all it takes to get set up.
2 changes: 1 addition & 1 deletion libs/scully-plugin-flash-prevention/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "scully-plugin-flash-prevention",
"version": "0.0.37",
"version": "0.0.38",
"peerDependencies": {
"@scullyio/scully": "^0.0.78"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { appendToHead } from './utils';

let AppRootSelector = 'app-root';
let LoadedClass = 'loaded';
let DisplayType = 'inherit';
const FlashPrevention = 'ScullyPluginFlashPrevention';
const AppRootAttrsBlacklist = ['_nghost', 'ng-version'];
const MockRootAttrsBlacklist = [];
Expand All @@ -14,6 +15,7 @@ registerPlugin('router', FlashPrevention, async ur => [{ route: ur }]);
interface FlashPreventionPluginOptions {
appRootSelector?: string;
appLoadedClass?: string;
displayType?: string;
appRootAttributesBlacklist?: string[];
mockAttributesBlacklist?: string[];
}
Expand All @@ -22,14 +24,18 @@ export function getFlashPreventionPlugin({
appRootSelector,
appLoadedClass,
appRootAttributesBlacklist,
mockAttributesBlacklist
mockAttributesBlacklist,
displayType
}: FlashPreventionPluginOptions = {}) {
if (appRootSelector) {
AppRootSelector = appRootSelector;
}
if (appLoadedClass) {
LoadedClass = appLoadedClass;
}
if (displayType) {
DisplayType = displayType;
}

pushItemsToArray(appRootAttributesBlacklist, AppRootAttrsBlacklist);
pushItemsToArray(mockAttributesBlacklist, MockRootAttrsBlacklist);
Expand Down Expand Up @@ -87,8 +93,8 @@ async function addBitsToHead(html) {
</script>
<style type="text/css">
body:not(.${LoadedClass}) ${AppRootSelector} { display:none; }
body:not(.${LoadedClass}) ${AppRootSelector}-scully { display:inherit; }
body.${LoadedClass} ${AppRootSelector} { display:inherit; }
body:not(.${LoadedClass}) ${AppRootSelector}-scully { display:${DisplayType}; }
body.${LoadedClass} ${AppRootSelector} { display:${DisplayType}; }
body.${LoadedClass} ${AppRootSelector}-scully { display:none; }
</style>
`;
Expand Down