| 
 | 1 | +/* global process */  | 
 | 2 | +import path from 'path';  | 
 | 3 | +import { fileURLToPath } from 'url';  | 
 | 4 | +import fs from 'fs-extra';  | 
 | 5 | +import log from 'fancy-log';  | 
 | 6 | + | 
 | 7 | +// Adapted into a script from: https://github.com/rafgraph/spa-github-pages/tree/gh-pages  | 
 | 8 | + | 
 | 9 | +const __filename = fileURLToPath(import.meta.url);  | 
 | 10 | +const __dirname = path.dirname(__filename);  | 
 | 11 | + | 
 | 12 | +const baseUrl = process.env.PUBLIC_URL || '';  | 
 | 13 | + | 
 | 14 | +const pathIndex = path.join(__dirname, '../src/index.html');  | 
 | 15 | +const path404 = path.join(__dirname, '../static/404.html');  | 
 | 16 | + | 
 | 17 | +async function main() {  | 
 | 18 | +  log.info('📦 Setting up single page apps on GitHub Pages.');  | 
 | 19 | + | 
 | 20 | +  const has404 = await fs.pathExists(path404);  | 
 | 21 | + | 
 | 22 | +  if (has404) {  | 
 | 23 | +    log.warn('📦 Found custom 404.html. Skipping setup.');  | 
 | 24 | +    process.exit(0);  | 
 | 25 | +  }  | 
 | 26 | + | 
 | 27 | +  if (!baseUrl) {  | 
 | 28 | +    log.warn(  | 
 | 29 | +      '📦 Public URL not set. Assuming the app is deployed to the root.'  | 
 | 30 | +    );  | 
 | 31 | +  }  | 
 | 32 | + | 
 | 33 | +  let segments = 0;  | 
 | 34 | +  if (baseUrl) {  | 
 | 35 | +    try {  | 
 | 36 | +      segments = new URL(baseUrl).pathname.split('/').length - 1;  | 
 | 37 | +      // eslint-disable-next-line @typescript-eslint/no-unused-vars  | 
 | 38 | +    } catch (error) {  | 
 | 39 | +      // no-op  | 
 | 40 | +    }  | 
 | 41 | +    log.info(`📦 Using ${baseUrl} with ${segments} path segments.`);  | 
 | 42 | +  }  | 
 | 43 | + | 
 | 44 | +  const templateScript = `<!-- Start Single Page Apps for GitHub Pages -->  | 
 | 45 | +    <script type="text/javascript">  | 
 | 46 | +      // Single Page Apps for GitHub Pages  | 
 | 47 | +      // MIT License  | 
 | 48 | +      // https://github.com/rafgraph/spa-github-pages  | 
 | 49 | +      // This script checks to see if a redirect is present in the query string,  | 
 | 50 | +      // converts it back into the correct url and adds it to the  | 
 | 51 | +      // browser's history using window.history.replaceState(...),  | 
 | 52 | +      // which won't cause the browser to attempt to load the new url.  | 
 | 53 | +      // When the single page app is loaded further down in this file,  | 
 | 54 | +      // the correct url will be waiting in the browser's history for  | 
 | 55 | +      // the single page app to route accordingly.  | 
 | 56 | +      (function(l) {  | 
 | 57 | +        if (l.search[1] === '/' ) {  | 
 | 58 | +          var decoded = l.search.slice(1).split('&').map(function(s) {   | 
 | 59 | +            return s.replace(/~and~/g, '&')  | 
 | 60 | +          }).join('?');  | 
 | 61 | +          window.history.replaceState(null, null,  | 
 | 62 | +              l.pathname.slice(0, -1) + decoded + l.hash  | 
 | 63 | +          );  | 
 | 64 | +        }  | 
 | 65 | +      }(window.location))  | 
 | 66 | +    </script>  | 
 | 67 | +    <!-- End Single Page Apps for GitHub Pages -->`;  | 
 | 68 | + | 
 | 69 | +  // Write to index head.  | 
 | 70 | +  const index = await fs.readFile(pathIndex, 'utf8');  | 
 | 71 | +  const newIndex = index.replace('<head>', `<head>\n${templateScript}`);  | 
 | 72 | +  await fs.writeFile(pathIndex, newIndex);  | 
 | 73 | + | 
 | 74 | +  const template404 = `<!DOCTYPE html>  | 
 | 75 | +<html>  | 
 | 76 | +  <head>  | 
 | 77 | +    <meta charset="utf-8">  | 
 | 78 | +    <title>Single Page Apps for GitHub Pages</title>  | 
 | 79 | +    <script type="text/javascript">  | 
 | 80 | +      // Single Page Apps for GitHub Pages  | 
 | 81 | +      // MIT License  | 
 | 82 | +      // https://github.com/rafgraph/spa-github-pages  | 
 | 83 | +      // This script takes the current url and converts the path and query  | 
 | 84 | +      // string into just a query string, and then redirects the browser  | 
 | 85 | +      // to the new url with only a query string and hash fragment,  | 
 | 86 | +      // e.g. https://www.foo.tld/one/two?a=b&c=d#qwe, becomes  | 
 | 87 | +      // https://www.foo.tld/?/one/two&a=b~and~c=d#qwe  | 
 | 88 | +      // Note: this 404.html file must be at least 512 bytes for it to work  | 
 | 89 | +      // with Internet Explorer (it is currently > 512 bytes)  | 
 | 90 | +
  | 
 | 91 | +      // If you're creating a Project Pages site and NOT using a custom domain,  | 
 | 92 | +      // then set pathSegmentsToKeep to 1 (enterprise users may need to set it to > 1).  | 
 | 93 | +      // This way the code will only replace the route part of the path, and not  | 
 | 94 | +      // the real directory in which the app resides, for example:  | 
 | 95 | +      // https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes  | 
 | 96 | +      // https://username.github.io/repo-name/?/one/two&a=b~and~c=d#qwe  | 
 | 97 | +      // Otherwise, leave pathSegmentsToKeep as 0.  | 
 | 98 | +      var pathSegmentsToKeep = ${segments};  | 
 | 99 | +
  | 
 | 100 | +      var l = window.location;  | 
 | 101 | +      l.replace(  | 
 | 102 | +        l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +  | 
 | 103 | +        l.pathname.split('/').slice(0, 1 + pathSegmentsToKeep).join('/') + '/?/' +  | 
 | 104 | +        l.pathname.slice(1).split('/').slice(pathSegmentsToKeep).join('/').replace(/&/g, '~and~') +  | 
 | 105 | +        (l.search ? '&' + l.search.slice(1).replace(/&/g, '~and~') : '') +  | 
 | 106 | +        l.hash  | 
 | 107 | +      );  | 
 | 108 | +
  | 
 | 109 | +    </script>  | 
 | 110 | +  </head>  | 
 | 111 | +  <body>  | 
 | 112 | +  </body>  | 
 | 113 | +</html>`;  | 
 | 114 | + | 
 | 115 | +  // Write to 404.html.  | 
 | 116 | +  await fs.writeFile(path404, template404);  | 
 | 117 | + | 
 | 118 | +  log.info('✅ GitHub Pages setup complete.');  | 
 | 119 | +}  | 
 | 120 | + | 
 | 121 | +main();  | 
0 commit comments