Skip to content
Permalink
Browse files

feat(No Javascript Plugin): Added all logic to remove JS from a Gatsb…

…y project.
  • Loading branch information
itmayziii committed Jun 26, 2019
0 parents commit 67bad8e36fa16c8a5a85ec58dd89cc6752519f9c
Showing with 197 additions and 0 deletions.
  1. +7 −0 .gitignore
  2. +4 −0 .npmignore
  3. +19 −0 LICENSE
  4. +1 −0 index.js
  5. +36 −0 package-lock.json
  6. +36 −0 package.json
  7. +73 −0 src/gatsby-ssr.ts
  8. +21 −0 tsconfig.json
@@ -0,0 +1,7 @@
node_modules/

# IDE #
.idea/

# Built Files #
gatsby-ssr.js
@@ -0,0 +1,4 @@
!gatsby-ssr.js

src/
tsconfig.json
19 LICENSE
@@ -0,0 +1,19 @@
Copyright (c) 2019 Tommy May III

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1 @@
// noop

Some generated files are not rendered by default. Learn more.

@@ -0,0 +1,36 @@
{
"name": "gatsby-plugin-no-javascript",
"version": "0.0.1",
"main": "index.js",
"description": "Removes all javascript files created by Gatsby from the static HTML files.",
"scripts": {
"build": "npx tsc --project tsconfig.json"
},
"repository": {
"type": "git",
"url": "git+https://github.com/itmayziii/gatsby-plugin-no-javascript.git"
},
"keywords": [
"gatsby",
"gatsby plugin",
"no javascript",
"remove",
"static"
],
"author": "Tommy May III <tommymay37@gmail.com>",
"contributors": [
"Mandar Mathure <mandarm2593@gmail.com>"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/itmayziii/gatsby-plugin-no-javascript/issues"
},
"homepage": "https://github.com/itmayziii/gatsby-plugin-no-javascript#readme",
"devDependencies": {
"@types/react": "^16.8.22",
"typescript": "^3.5.2"
},
"peerDependencies": {
"gatsby": "^2.0.0"
}
}
@@ -0,0 +1,73 @@
import { ReactElement, ReactNode } from 'react'

interface OnRenderBodyArgs {
scripts?: Scripts[]
}

interface OnPreRenderHTMLArgs {
getHeadComponents (): ReactNode[]
replaceHeadComponents (reactNodes: ReactNode[]): void
getPostBodyComponents (): ReactNode[]
replacePostBodyComponents (ReactNode: ReactNode[]): void
}

interface Scripts {
name: string
rel: string
}

let pageScripts: Scripts[]

/*
* The "scripts" variable is not documented by Gatsby, https://www.gatsbyjs.org/docs/ssr-apis/#onRenderBody, and that is probably for a good reason. The variable contains
* the scripts the Gatsby internals, https://github.com/gatsbyjs/gatsby/blob/d9cf5a21403c474846ebdf7a0508902b9b8a2ea9/packages/gatsby/cache-dir/static-entry.js#L270-L283, puts into
* the head and post body. We will be relying on this undocumented variable until it does not work anymore as the alternative is to read the webpack.stats.json file and parse it ourselves.
*/
export function onRenderBody ({ scripts }: OnRenderBodyArgs) {
// TODO maybe we should not even wait and see if Gatsby removes this internal "script" variable and code around the issue if the variable is not there.
if (!scripts) {
throw new Error('gatsby-plugin-no-javascript: Gatsby removed an internal detail that this plugin relied upon, please submit this issue to https://www.github.com/itmayziii/gatsby-plugin-no-javascript.')
}
pageScripts = scripts
}

// Here we rely on the fact that onPreRenderHTML is called after onRenderBody so we have access to the scripts Gatsby inserted into the HTML.
export function onPreRenderHTML ({ getHeadComponents, replaceHeadComponents, getPostBodyComponents, replacePostBodyComponents }: OnPreRenderHTMLArgs) {
replaceHeadComponents(getHeadComponentsNoJS(getHeadComponents()))
replacePostBodyComponents(getPostBodyComponentsNoJS(getPostBodyComponents()))
}

function getHeadComponentsNoJS (headComponents: ReactNode[]): ReactNode[] {
return headComponents.filter((headComponent) => {
// Not a react component and therefore not a <script>.
if (!isReactElement(headComponent)) {
return true
}

return pageScripts.find((script) => {
const matchesScript = headComponent.props.as === 'script' && `/${script.name}` === headComponent.props.href && script.rel === headComponent.props.rel
const isJSONFile = headComponent.props.href && headComponent.props.href.endsWith('.json')
return matchesScript || isJSONFile
}) === undefined
})
}

function getPostBodyComponentsNoJS (postBodyComponents: ReactNode[]): ReactNode[] {
return postBodyComponents.filter((postBodyComponent) => {
// Not a react component and therefore not a <script>.
if (!isReactElement(postBodyComponent)) {
return true
}

// These are special Gatsby files we are calling out specifically.
if (postBodyComponent.props.id && (postBodyComponent.props.id === 'gatsby-script-loader' || postBodyComponent.props.id === 'gatsby-chunk-mapping')) {
return false
}

return pageScripts.find((script) => postBodyComponent.type === 'script' && `/${script.name}` === postBodyComponent.props.src) === undefined
})
}

function isReactElement (reactNode: ReactNode): reactNode is ReactElement {
return (<ReactElement>reactNode).props !== undefined
}
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"outDir": "./",
"strict": true,
"target": "es5",
"moduleResolution": "node",
"rootDir": "src",
"lib": [
"es6",
"dom"
]
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"dist",
"**/*.spec.ts"
]
}

0 comments on commit 67bad8e

Please sign in to comment.
You can’t perform that action at this time.