next-ssg-transform.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = nextTransformSsg;
  6. exports.EXPORT_NAME_GET_SERVER_PROPS = exports.EXPORT_NAME_GET_STATIC_PATHS = exports.EXPORT_NAME_GET_STATIC_PROPS = void 0;
  7. var _constants = require("../../../lib/constants");
  8. var _constants1 = require("../../../shared/lib/constants");
  9. function nextTransformSsg({ types: t }) {
  10. function getIdentifier(path) {
  11. const parentPath = path.parentPath;
  12. if (parentPath.type === "VariableDeclarator") {
  13. const pp = parentPath;
  14. const name = pp.get("id");
  15. return name.node.type === "Identifier" ? name : null;
  16. }
  17. if (parentPath.type === "AssignmentExpression") {
  18. const pp = parentPath;
  19. const name = pp.get("left");
  20. return name.node.type === "Identifier" ? name : null;
  21. }
  22. if (path.node.type === "ArrowFunctionExpression") {
  23. return null;
  24. }
  25. return path.node.id && path.node.id.type === "Identifier" ? path.get("id") : null;
  26. }
  27. function isIdentifierReferenced(ident) {
  28. const b = ident.scope.getBinding(ident.node.name);
  29. if (b == null ? void 0 : b.referenced) {
  30. // Functions can reference themselves, so we need to check if there's a
  31. // binding outside the function scope or not.
  32. if (b.path.type === "FunctionDeclaration") {
  33. return !b.constantViolations.concat(b.referencePaths)// Check that every reference is contained within the function:
  34. .every((ref)=>ref.findParent((p)=>p === b.path));
  35. }
  36. return true;
  37. }
  38. return false;
  39. }
  40. function markFunction(path, state) {
  41. const ident = getIdentifier(path);
  42. if ((ident == null ? void 0 : ident.node) && isIdentifierReferenced(ident)) {
  43. state.refs.add(ident);
  44. }
  45. }
  46. function markImport(path, state) {
  47. const local = path.get("local");
  48. if (isIdentifierReferenced(local)) {
  49. state.refs.add(local);
  50. }
  51. }
  52. return {
  53. visitor: {
  54. Program: {
  55. enter (path, state) {
  56. state.refs = new Set();
  57. state.isPrerender = false;
  58. state.isServerProps = false;
  59. state.done = false;
  60. path.traverse({
  61. VariableDeclarator (variablePath, variableState) {
  62. if (variablePath.node.id.type === "Identifier") {
  63. const local = variablePath.get("id");
  64. if (isIdentifierReferenced(local)) {
  65. variableState.refs.add(local);
  66. }
  67. } else if (variablePath.node.id.type === "ObjectPattern") {
  68. const pattern = variablePath.get("id");
  69. const properties = pattern.get("properties");
  70. properties.forEach((p)=>{
  71. const local = p.get(p.node.type === "ObjectProperty" ? "value" : p.node.type === "RestElement" ? "argument" : function() {
  72. throw new Error("invariant");
  73. }());
  74. if (isIdentifierReferenced(local)) {
  75. variableState.refs.add(local);
  76. }
  77. });
  78. } else if (variablePath.node.id.type === "ArrayPattern") {
  79. const pattern = variablePath.get("id");
  80. const elements = pattern.get("elements");
  81. elements.forEach((e)=>{
  82. var ref, ref1;
  83. let local;
  84. if (((ref = e.node) == null ? void 0 : ref.type) === "Identifier") {
  85. local = e;
  86. } else if (((ref1 = e.node) == null ? void 0 : ref1.type) === "RestElement") {
  87. local = e.get("argument");
  88. } else {
  89. return;
  90. }
  91. if (isIdentifierReferenced(local)) {
  92. variableState.refs.add(local);
  93. }
  94. });
  95. }
  96. },
  97. FunctionDeclaration: markFunction,
  98. FunctionExpression: markFunction,
  99. ArrowFunctionExpression: markFunction,
  100. ImportSpecifier: markImport,
  101. ImportDefaultSpecifier: markImport,
  102. ImportNamespaceSpecifier: markImport,
  103. ExportNamedDeclaration (exportNamedPath, exportNamedState) {
  104. const specifiers = exportNamedPath.get("specifiers");
  105. if (specifiers.length) {
  106. specifiers.forEach((s)=>{
  107. if (isDataIdentifier(t.isIdentifier(s.node.exported) ? s.node.exported.name : s.node.exported.value, exportNamedState)) {
  108. s.remove();
  109. }
  110. });
  111. if (exportNamedPath.node.specifiers.length < 1) {
  112. exportNamedPath.remove();
  113. }
  114. return;
  115. }
  116. const decl = exportNamedPath.get("declaration");
  117. if (decl == null || decl.node == null) {
  118. return;
  119. }
  120. switch(decl.node.type){
  121. case "FunctionDeclaration":
  122. {
  123. const name = decl.node.id.name;
  124. if (isDataIdentifier(name, exportNamedState)) {
  125. exportNamedPath.remove();
  126. }
  127. break;
  128. }
  129. case "VariableDeclaration":
  130. {
  131. const inner = decl.get("declarations");
  132. inner.forEach((d)=>{
  133. if (d.node.id.type !== "Identifier") {
  134. return;
  135. }
  136. const name = d.node.id.name;
  137. if (isDataIdentifier(name, exportNamedState)) {
  138. d.remove();
  139. }
  140. });
  141. break;
  142. }
  143. default:
  144. {
  145. break;
  146. }
  147. }
  148. }
  149. }, state);
  150. if (!state.isPrerender && !state.isServerProps) {
  151. return;
  152. }
  153. const refs = state.refs;
  154. let count;
  155. function sweepFunction(sweepPath) {
  156. const ident = getIdentifier(sweepPath);
  157. if ((ident == null ? void 0 : ident.node) && refs.has(ident) && !isIdentifierReferenced(ident)) {
  158. ++count;
  159. if (t.isAssignmentExpression(sweepPath.parentPath) || t.isVariableDeclarator(sweepPath.parentPath)) {
  160. sweepPath.parentPath.remove();
  161. } else {
  162. sweepPath.remove();
  163. }
  164. }
  165. }
  166. function sweepImport(sweepPath) {
  167. const local = sweepPath.get("local");
  168. if (refs.has(local) && !isIdentifierReferenced(local)) {
  169. ++count;
  170. sweepPath.remove();
  171. if (sweepPath.parent.specifiers.length === 0) {
  172. sweepPath.parentPath.remove();
  173. }
  174. }
  175. }
  176. do {
  177. path.scope.crawl();
  178. count = 0;
  179. path.traverse({
  180. // eslint-disable-next-line no-loop-func
  181. VariableDeclarator (variablePath) {
  182. if (variablePath.node.id.type === "Identifier") {
  183. const local = variablePath.get("id");
  184. if (refs.has(local) && !isIdentifierReferenced(local)) {
  185. ++count;
  186. variablePath.remove();
  187. }
  188. } else if (variablePath.node.id.type === "ObjectPattern") {
  189. const pattern = variablePath.get("id");
  190. const beforeCount = count;
  191. const properties = pattern.get("properties");
  192. properties.forEach((p)=>{
  193. const local = p.get(p.node.type === "ObjectProperty" ? "value" : p.node.type === "RestElement" ? "argument" : function() {
  194. throw new Error("invariant");
  195. }());
  196. if (refs.has(local) && !isIdentifierReferenced(local)) {
  197. ++count;
  198. p.remove();
  199. }
  200. });
  201. if (beforeCount !== count && pattern.get("properties").length < 1) {
  202. variablePath.remove();
  203. }
  204. } else if (variablePath.node.id.type === "ArrayPattern") {
  205. const pattern = variablePath.get("id");
  206. const beforeCount = count;
  207. const elements = pattern.get("elements");
  208. elements.forEach((e)=>{
  209. var ref, ref2;
  210. let local;
  211. if (((ref = e.node) == null ? void 0 : ref.type) === "Identifier") {
  212. local = e;
  213. } else if (((ref2 = e.node) == null ? void 0 : ref2.type) === "RestElement") {
  214. local = e.get("argument");
  215. } else {
  216. return;
  217. }
  218. if (refs.has(local) && !isIdentifierReferenced(local)) {
  219. ++count;
  220. e.remove();
  221. }
  222. });
  223. if (beforeCount !== count && pattern.get("elements").length < 1) {
  224. variablePath.remove();
  225. }
  226. }
  227. },
  228. FunctionDeclaration: sweepFunction,
  229. FunctionExpression: sweepFunction,
  230. ArrowFunctionExpression: sweepFunction,
  231. ImportSpecifier: sweepImport,
  232. ImportDefaultSpecifier: sweepImport,
  233. ImportNamespaceSpecifier: sweepImport
  234. });
  235. }while (count);
  236. decorateSsgExport(t, path, state);
  237. }
  238. }
  239. }
  240. };
  241. }
  242. const EXPORT_NAME_GET_STATIC_PROPS = "getStaticProps";
  243. exports.EXPORT_NAME_GET_STATIC_PROPS = EXPORT_NAME_GET_STATIC_PROPS;
  244. const EXPORT_NAME_GET_STATIC_PATHS = "getStaticPaths";
  245. exports.EXPORT_NAME_GET_STATIC_PATHS = EXPORT_NAME_GET_STATIC_PATHS;
  246. const EXPORT_NAME_GET_SERVER_PROPS = "getServerSideProps";
  247. exports.EXPORT_NAME_GET_SERVER_PROPS = EXPORT_NAME_GET_SERVER_PROPS;
  248. const ssgExports = new Set([
  249. EXPORT_NAME_GET_STATIC_PROPS,
  250. EXPORT_NAME_GET_STATIC_PATHS,
  251. EXPORT_NAME_GET_SERVER_PROPS,
  252. // legacy methods added so build doesn't fail from importing
  253. // server-side only methods
  254. `unstable_getStaticProps`,
  255. `unstable_getStaticPaths`,
  256. `unstable_getServerProps`,
  257. `unstable_getServerSideProps`,
  258. ]);
  259. function decorateSsgExport(t, path, state) {
  260. const gsspName = state.isPrerender ? _constants1.STATIC_PROPS_ID : _constants1.SERVER_PROPS_ID;
  261. const gsspId = t.identifier(gsspName);
  262. const addGsspExport = (exportPath)=>{
  263. if (state.done) {
  264. return;
  265. }
  266. state.done = true;
  267. const [pageCompPath] = exportPath.replaceWithMultiple([
  268. t.exportNamedDeclaration(t.variableDeclaration(// We use 'var' instead of 'let' or 'const' for ES5 support. Since
  269. // this runs in `Program#exit`, no ES2015 transforms (preset env)
  270. // will be ran against this code.
  271. "var", [
  272. t.variableDeclarator(gsspId, t.booleanLiteral(true))
  273. ]), [
  274. t.exportSpecifier(gsspId, gsspId)
  275. ]),
  276. exportPath.node,
  277. ]);
  278. exportPath.scope.registerDeclaration(pageCompPath);
  279. };
  280. path.traverse({
  281. ExportDefaultDeclaration (exportDefaultPath) {
  282. addGsspExport(exportDefaultPath);
  283. },
  284. ExportNamedDeclaration (exportNamedPath) {
  285. addGsspExport(exportNamedPath);
  286. }
  287. });
  288. }
  289. const isDataIdentifier = (name, state)=>{
  290. if (ssgExports.has(name)) {
  291. if (name === EXPORT_NAME_GET_SERVER_PROPS) {
  292. if (state.isPrerender) {
  293. throw new Error(_constants.SERVER_PROPS_SSG_CONFLICT);
  294. }
  295. state.isServerProps = true;
  296. } else {
  297. if (state.isServerProps) {
  298. throw new Error(_constants.SERVER_PROPS_SSG_CONFLICT);
  299. }
  300. state.isPrerender = true;
  301. }
  302. return true;
  303. }
  304. return false;
  305. };
  306. //# sourceMappingURL=next-ssg-transform.js.map