Skip to content

Commit

Permalink
fix(gatsby): remove unused vars in remove api plugin (gatsbyjs#33476)
Browse files Browse the repository at this point in the history
  • Loading branch information
wardpeet authored Oct 12, 2021
1 parent 1dd00b7 commit 3002d65
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 0 deletions.
7 changes: 7 additions & 0 deletions e2e-tests/development-runtime/src/pages/ssr/static-path.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from "react"
import path from "path"
import * as fs from "fs"

export default function StaticPath({ serverData }) {
return (
Expand All @@ -14,8 +16,13 @@ export default function StaticPath({ serverData }) {
}

export function getServerData(arg) {
const pkgJSON = JSON.parse(
fs.readFileSync(path.join(__dirname, "../../../package.json"), "utf8")
)

return {
props: {
version: pkgJSON.version,
arg,
},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as fs from "fs"

const { fetch, Response } = require('node-fetch');
const unusedReference = fs.readFileSync('./myfile.json');
const usedReference = 'used reference';

module.exports = function () {
const x = new Response({})

return usedReference
}

exports.getServerData = async function getServerData() {
const data = await fetch('https://example.com');
const file = fs.readFileSync('./unknown.tmp.json', 'utf8')

return {
props: {
file,
}
}
}

exports.config = function config() {
return {
pageContext: {
env: 'test',
unusedReference,
},
}
}

exports.anotherFunction = function anotherFunction() {
return "test"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const {
Response
} = require('node-fetch');

const usedReference = 'used reference';

module.exports = function () {
const x = new Response({});
return usedReference;
};

exports.anotherFunction = function anotherFunction() {
return "test";
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { fetch, Response } from 'node-fetch';
import something from 'my-import'
import * as fs from "fs"

const usedReference = 'my cool ref';
const unusedReference = 'I hope to be removed';
const { x, y } = require('some-import');

export default function () {
const x = new Response({})
anotherSelfReferencedOne();

return usedReference
}

// such a structure is being generated by regenerator-runtime
function renderPage() {
renderPage = () => { };
}

function anotherSelfReferencedOne() {
anotherSelfReferencedOne = () => { };
}

export async function getServerData() {
const data = await fetch('https://example.com');
const file = fs.readFileSync('./unknown.tmp.json', 'utf8')
renderPage();
anotherSelfReferencedOne();

return {
props: {
x,
y,
file,
data: await data.json(),
unusedReference,
test: something(),
}

}
}

export function config() {
return {
pageContext: {
env: 'test',
unusedReference,
},
}
}

export function anotherFunction() {
return "test"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Response } from 'node-fetch';
const usedReference = 'my cool ref';
export default function () {
const x = new Response({});
anotherSelfReferencedOne();
return usedReference;
} // such a structure is being generated by regenerator-runtime

function anotherSelfReferencedOne() {
anotherSelfReferencedOne = () => {};
}

export function anotherFunction() {
return "test";
}
88 changes: 88 additions & 0 deletions packages/gatsby/src/utils/babel/babel-plugin-remove-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,77 @@ export default declare(function removeApiCalls(
return {
name: `remove-api`,
visitor: {
Program: {
exit(path): void {
// babel doesn't remove references very well so we loop until nothing gets removed
let removed = false

// remove all unreferenced bindings
do {
removed = false
// make sure all references are up to date
path.scope.crawl()

Object.keys(path.scope.bindings).forEach(refName => {
const ref = path.scope.bindings[refName]

if (ref.referenced) {
// Functions can reference themselves, so we need to check if there's a
// binding outside the function scope or not.
if (ref.path.type === `FunctionDeclaration`) {
const isSelfReferenced = ref.referencePaths.every(
refPath => !!refPath.findParent(p => p === ref.path)
)

if (isSelfReferenced) {
ref.path.remove()
removed = true
}
}
} else {
// if const {x,y} is used, we remove the property
if (
t.isVariableDeclarator(ref.path) &&
t.isObjectPattern(
(ref.path.parent as t.VariableDeclaration).declarations[0]
.id
)
) {
const objectPattern = (
ref.path.parent as t.VariableDeclaration
).declarations[0].id as t.ObjectPattern
objectPattern.properties = objectPattern.properties.filter(
prop =>
t.isObjectProperty(prop)
? (prop.value as t.Identifier).name !== refName
: ((prop as t.RestElement).argument as t.Identifier)
.name !== refName
)

// if all properties got removed thus the object pattern is empty, we remove the whole declaration
if (!objectPattern.properties.length) {
ref.path.remove()
}
} else {
ref.path.remove()
}

// if it's a module and all specifiers are removed, remove the full binding
if (
ref.kind === `module` &&
!(ref.path.parent as t.ImportDeclaration).specifiers.length
) {
ref.path.parentPath.remove()
}

removed = true
}
})
} while (removed)
},
},

// Remove export statements
ExportNamedDeclaration(path): void {
const declaration = path.node.declaration

Expand Down Expand Up @@ -58,6 +129,23 @@ export default declare(function removeApiCalls(
path.remove()
}
},

// remove exports
ExpressionStatement(path): void {
if (
!t.isAssignmentExpression(path.node.expression) ||
!t.isMemberExpression(path.node.expression.left) ||
(path.node.expression.left.object as t.Identifier).name !== `exports`
) {
return
}

const apiToCheck = (path.node.expression.left.property as t.Identifier)
.name
if (apiToCheck && apisToRemove.includes(apiToCheck)) {
path.remove()
}
},
},
}
})

0 comments on commit 3002d65

Please sign in to comment.