Skip to content

Commit

Permalink
fix(lib): removeScriptPlugn(fix) make sure _all_ scripts are removed (s…
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderElias authored Sep 22, 2020
1 parent 43e4932 commit 8976147
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 45 deletions.
6 changes: 1 addition & 5 deletions apps/sample-blog/browserslist
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,4 @@
# You can see what browsers were selected by your queries by running:
# npx browserslist

> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.
last 2 Chrome versions
6 changes: 1 addition & 5 deletions apps/scully-docs/browserslist
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,4 @@
# You can see what browsers were selected by your queries by running:
# npx browserslist

> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.
last 2 Chrome versions
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export const googleAnalyticsPlugin = async (html: string): Promise<string> => {

const googleAnalyticsScript = `
<!-- Google Analytics -->
<script>
<script sk>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', '${siteTag}', 'auto');
ga('send', 'pageview');
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>
<script sk async src='https://www.google-analytics.com/analytics.js'></script>
<!-- End Google Analytics -->
`;

Expand Down
4 changes: 2 additions & 2 deletions libs/plugins/logrocket/src/lib/plugins-logrocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export const logrocketPlugin = async (html: string): Promise<string> => {
}

const logrocketScript = `
<script src="https://cdn.logrocket.io/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('${logrocketConfig['app']}/${logrocketConfig['id']}');</script>`;
<script sk src="https://cdn.logrocket.io/LogRocket.min.js"></script>
<script sk>window.LogRocket && window.LogRocket.init('${logrocketConfig['app']}/${logrocketConfig['id']}');</script>`;

return html.replace(/<\/head/i, `${logrocketScript}</head`);
};
Expand Down
52 changes: 50 additions & 2 deletions libs/plugins/scully-plugin-remove-scripts/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,52 @@
# plugins-scully-plugin-remove-scripts

This is a WIP.
The goal is to have a plugin that removes the script tags from the bottom of the page.
This plugin will remove all the scripts tags from the incoming HTML. If you don't want to remove _all_ you can use some of the options.

```typescript
export interface RemoveScriptsConfig {
/** function that receives the script element and returns false when the script needs to be removed */
predicate?: (elm: HTMLScriptElement) => boolean;
/** defaults to true, keeps the transferState so the data.json can be generated */
keepTransferstate?: boolean;
/** defaults to `['scullyKeep', 'sk']`. array with attributes, scripts that have one of those will be kept */
keepAttributes?: string[];
/** defaults to `[]`. Array with strings, if the fragment occurs in the SRC of the script. the script is kept*/
keepSrc?: string[];
}
```

You can use this plugin in scully by adding something like this to your `scully.<projectname>.config.ts`

```typescript
import { removeScripts, RemoveScriptsConfig } from '@scullyio/plugins/scully-plugin-remove-scripts';

const defaultPostRenderers = [removeScripts, 'seoHrefOptimise'];
setPluginConfig<RemoveScriptsConfig>(removeScripts, {
keepTransferstate: false,
/** overwrite default by empty string! */
keepAttributes: []
});

export const config: ScullyConfig = {
...
defaultPostRenderers: = [removeScripts],
routes: {
...
}
}
```

The above config will use the plugin on _all_ routes. If you want to use in on a single route, add it to the config of that particular route like this:

```typescript
export const config: ScullyConfig = {
...
routes: {
someRoute: {
type: 'contentFolder', // Or any other type
postRenderers: = [removeScripts],
}
...
}
}
```
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import { HandledRoute, logWarn, registerPlugin, yellow, getMyConfig } from '@scullyio/scully';
import { JSDOM } from 'jsdom';

export const removeBottomScripts = 'removeBottomScripts';
export const removeScripts = 'removeScripts';
export interface RemoveScriptsConfig {
/** function that receives the script element and returns false when the script needs to be removed */
predicate?: (elm: HTMLScriptElement) => boolean;
/** defaults to true, keeps the transferState so the data.json can be generated */
keepTransferstate?: boolean;
/** defaults to `['scullyKeep', 'sk']`. array with attributes, scripts that have one of those will be kept */
keepAttributes?: string[];
/** defaults to `[]`. Array with strings, if the fragment occurs in the SRC of the script. the script is kept*/
keepSrc?: string[];
}

const config = {
const config: RemoveScriptsConfig = {
predicate: (elm) => false,
keepTransferstate: true,
keepAttribute: 'scullyKeep',
keepAttributes: ['scullyKeep', 'sk'],
keepSrc: [],
};

const plugin = async (html: string, route: HandledRoute) => {
Expand All @@ -15,26 +26,27 @@ const plugin = async (html: string, route: HandledRoute) => {
const dom = new JSDOM(html);
const { window } = dom;
const { document } = window;
let elm = document.body.lastElementChild;
while (elm.tagName === 'SCRIPT') {
const cur = elm;
elm = cur.previousElementSibling;
document.querySelectorAll('script').forEach((cur) => {
if (conf.keepTransferstate && cur.id === 'ScullyIO-transfer-state') {
break;
return;
}
if (conf.predicate(cur)) {
break;
return;
}
if (cur.hasAttribute(conf.keepAttribute)) {
break;
if (conf.keepAttributes.some((attribute) => cur.hasAttribute(attribute))) {
return;
}
document.body.removeChild(cur);
}
if (conf.keepSrc.some((s) => cur.src.includes(s))) {
return;
}
// console.log('removed', cur.src || cur.innerHTML);
cur.parentNode.removeChild(cur);
});
return dom.serialize();
} catch (e) {
logWarn(`error in ${removeBottomScripts}, didn't parse for route "${yellow(route.route)}"`);
logWarn(`error in ${removeScripts}, didn't parse for route "${yellow(route.route)}"`);
}
return html;
};

registerPlugin('render', removeBottomScripts, plugin);
registerPlugin('render', removeScripts, plugin);
14 changes: 8 additions & 6 deletions libs/scully/src/lib/pluginManagement/pluginConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,25 @@ export const routeConfigData = configData + 'Route_Config_Data__';
export const resetConfig = configData + 'resetData__';

interface SetPluginConfig {
<T>(name: string | symbol, configData: T): void;
<T>(name: string | symbol, type: PluginTypes, configData: T): void;
(name: string | symbol, configData: Serializable): void;
(name: string | symbol, type: PluginTypes, configData: Serializable): void;
}
export const setPluginConfig: SetPluginConfig = (
export const setPluginConfig: SetPluginConfig = <T>(
name: string,
typeOrConfig: PluginTypes | Serializable,
config?: Serializable
typeOrConfig: PluginTypes | Serializable | T,
config?: Serializable | T
): void => {
let type: string;
// tslint:disable-next-line: no-angle-bracket-type-assertion
if ((typeof typeOrConfig === 'string' || typeof typeOrConfig === 'symbol') && pluginTypes.includes(<any>typeOrConfig)) {
type = typeOrConfig;
type = (typeOrConfig as unknown) as string;
} else {
config = (typeOrConfig as unknown) as Serializable;
}
const plugin = findPlugin(name, type);
setConfig(plugin, config);
setConfig<T>(plugin, config);
};

export const getPluginConfig = <T>(name: string | symbol, type?: string): T => {
Expand Down Expand Up @@ -75,7 +77,7 @@ export const getConfig = <T>(plugin: any): T => {
return target[configData] || ({} as T);
};

export const setConfig = (plugin: any, config: Serializable): void => {
export const setConfig = <T>(plugin: any, config: Serializable | T): void => {
const target = plugin.hasOwnProperty(accessPluginDirectly) ? plugin[accessPluginDirectly] : plugin;
target[configData] = Object.assign({}, target[configData] || {}, config);
target[backupData] = { ...target[configData] };
Expand Down
4 changes: 2 additions & 2 deletions scully.sample-blog.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import '@scullyio/scully-plugin-from-data';
import './demos/plugins/errorPlugin';
import './demos/plugins/tocPlugin';
import './demos/plugins/voidPlugin';
import { removeBottomScripts } from '@scullyio/plugins/scully-plugin-remove-scripts';
import { removeScripts } from '@scullyio/plugins/scully-plugin-remove-scripts';
import { RouteConfig } from '@scullyio/scully/lib/routerPlugins';
import { docLink } from '@scullyio/scully-plugin-docs-link-update';

Expand Down Expand Up @@ -146,7 +146,7 @@ export const config: ScullyConfig = {
},
'/noScript': {
type: 'default',
postRenderers: [removeBottomScripts],
postRenderers: [removeScripts],
},
'/rawRoute': {
type: 'rawTest',
Expand Down
9 changes: 7 additions & 2 deletions scully.scully-docs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { docLink } from '@scullyio/scully-plugin-docs-link-update';
import { GoogleAnalytics } from '@scullyio/scully-plugin-google-analytics';
import { LogRocket } from '@scullyio/scully-plugin-logrocket';
import { Sentry } from '@scullyio/scully-plugin-sentry';
import { removeBottomScripts } from '@scullyio/plugins/scully-plugin-remove-scripts';
import { removeScripts, RemoveScriptsConfig } from '@scullyio/plugins/scully-plugin-remove-scripts';
const marked = require('marked');
import { readFileSync } from 'fs-extra';
import { JSDOM } from 'jsdom';
Expand All @@ -15,7 +15,7 @@ const { document } = window;

setPluginConfig('md', { enableSyntaxHighlighting: true });

const defaultPostRenderers = [LogRocket, GoogleAnalytics, removeBottomScripts];
const defaultPostRenderers = [LogRocket, GoogleAnalytics, removeScripts, 'seoHrefOptimise'];

if (prod) {
/*
Expand All @@ -40,6 +40,11 @@ if (prod) {
setPluginConfig(GoogleAnalytics, { globalSiteTag: 'test' });
}

setPluginConfig<RemoveScriptsConfig>(removeScripts, {
keepTransferstate: false,
keepAttributes: [],
});

export const config: ScullyConfig = {
projectRoot: './apps/scully-docs/src',
projectName: 'scully-docs',
Expand Down
8 changes: 4 additions & 4 deletions workspace.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@
"polyfills": "apps/scully-docs/src/polyfills.ts",
"tsConfig": "apps/scully-docs/tsconfig.app.json",
"aot": true,
"statsJson": true,
"statsJson": false,
"assets": ["apps/scully-docs/src/favicon.ico", "apps/scully-docs/src/assets"],
"styles": [
"apps/scully-docs/src/app/app.component.css",
Expand Down Expand Up @@ -245,14 +245,14 @@
}
],
"optimization": true,
"outputHashing": "all",
"outputHashing": "none",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"namedChunks": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"statsJson": true,
"statsJson": false,
"budgets": [
{
"type": "initial",
Expand Down

0 comments on commit 8976147

Please sign in to comment.