Advertisement
Guest User

Untitled

a guest
Aug 23rd, 2019
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const path = require('path');
  2. const fs = require('fs');
  3. const cmdArgs = require('command-line-args');
  4. const workboxBuild = require('workbox-build');
  5.  
  6. // This script file's absolute path
  7. const SCRIPT_PATH = __dirname;
  8. // Repository absolute path
  9. const ROOT_PATH = path.resolve(SCRIPT_PATH, '..');
  10. // Default absolute path for generated service worker files
  11. const OUTPUT_BASE_PATH = path.join('sites', 'site_template', 'sites', 'ASDA', 'library', 'static', 'default', 'ServiceWorker');
  12. // Arguments structure
  13. const OPTIONS_DEFINITION = [
  14.   { name: 'exclude-dev', alias: 'D', type: Boolean },
  15.   { name: 'exclude-stg', alias: 'S', type: Boolean },
  16.   { name: 'exclude-prod', alias: 'P', type: Boolean },
  17.   { name: 'exclude-dep', alias: 'd', type: Boolean },
  18.   { name: 'exclude-old', alias: 'o', type: Boolean },
  19.   { name: 'exclude-both', alias: 'b', type: Boolean },
  20.   { name: 'exclude-uncached', alias: 'u', type: Boolean },
  21.   { name: 'output-path', alias: 'p', type: String, defaultOption: true, defaultValue: '.' },
  22.   { name: 'output-files', alias: 'f', type: String, defaultValue: 'sw-{env}-{ver}.js' },
  23.   { name: 'help', alias: 'h', type: Boolean }
  24. ];
  25.  
  26. main();
  27.  
  28. /**
  29.  * Main function of the script
  30.  * @returns {void}
  31.  */
  32. function main() {
  33.   let options;
  34.   try {
  35.     try {
  36.       options = cmdArgs(OPTIONS_DEFINITION);
  37.       if (options['exclude-dev'] && options['exclude-stg'] && options['exclude-prod']) {
  38.         options = null;
  39.         throw new Error('At least one environment must be NOT excluded');
  40.       }
  41.       if (options['exclude-dep'] && options['exclude-old'] && options['exclude-both'] && options['exclude-uncached']) {
  42.         options = null;
  43.         throw new Error('At least one version must be NOT excluded');
  44.       }
  45.     } catch (e) {
  46.       console.error('Invalid arguments (' + e.message + '). Use --help or -h for help.');
  47.     }
  48.     if (options && options['help']) {
  49.       getHelpContent().then((data) => console.log(data));
  50.     } else if (options) {
  51.       generateAllServiceWorkers(
  52.         !options['exclude-dev'],
  53.         !options['exclude-stg'],
  54.         !options['exclude-prod'],
  55.         !options['exclude-dep'],
  56.         !options['exclude-old'],
  57.         !options['exclude-both'],
  58.         !options['exclude-uncached'],
  59.         path.resolve(ROOT_PATH, OUTPUT_BASE_PATH, options['output-path']),
  60.         options['output-files']
  61.       );
  62.     }
  63.   } catch (e) {
  64.     console.error(e);
  65.   }
  66. };
  67.  
  68. /**
  69.  * Gets the help (--help | -h) text from README.md
  70.  * @returns {Promise}  Resolves to README content or rejects with file operation error
  71.  */
  72. function getHelpContent() {
  73.   return new Promise(function(resolve, reject) {
  74.     fs.readFile(path.resolve(SCRIPT_PATH, 'README.md'), 'utf8', (e, data) => {
  75.       e ? reject(e) : resolve(data);
  76.     });
  77.   });
  78. }
  79.  
  80. /**
  81.  * Generates all service worker files.
  82.  * @param {boolean} isDev  Whether to generate 'dev' (Development) files
  83.  * @param {boolean} isStg  Whether to generate 'stg' (Staging) files
  84.  * @param {boolean} isProd  Whether to generate 'prod' (Production) files
  85.  * @param {boolean} isDep  Whether to generate 'dep' (DEP site) files
  86.  * @param {boolean} isOld  Whether to generate 'old' (Classic site) files
  87.  * @param {boolean} isBoth  Whether to generate 'both' (combined DEP and Classic) files
  88.  * @param {boolean} isUncached  Whether to generate 'nocache' (no pre-caching) files
  89.  * @param {string} outputPath  Destination directory (best use absolute path to avoid any relativity issues)
  90.  * @returns {void}
  91.  */
  92. function generateAllServiceWorkers(isDev, isStg, isProd, isDep, isOld, isBoth, isUncached, outputPath, filenameTemplate) {
  93.   console.log('Generating service worker file(s) in:\n' + outputPath);
  94.   let assetList = {
  95.     'main': path.resolve(SCRIPT_PATH, './blueprints/master-sw-blueprint.js'),
  96.     'dev': isDev ? path.resolve(SCRIPT_PATH, './blueprints/partials/dev-partial-sw-blueprint.js') : '',
  97.     'stg': isStg ? path.resolve(SCRIPT_PATH, './blueprints/partials/stg-partial-sw-blueprint.js') : '',
  98.     'prod': isProd ? path.resolve(SCRIPT_PATH, './blueprints/partials/prod-partial-sw-blueprint.js') : ''
  99.   };
  100.   let patternList = {
  101.     'dep': 'app_asda_react/cartridge/static/default/react/assets/**\/*.{js,css,svg}',
  102.     'old': 'app_asda_responsive/cartridge/static/default/responsive/**\/*.{mini.js,min.js,css,svg}'
  103.   };
  104.   let envList = [];
  105.   isDev && envList.push('dev');
  106.   isStg && envList.push('stg');
  107.   isProd && envList.push('prod');
  108.   let verList = [];
  109.   isDep && verList.push('dep');
  110.   isOld && verList.push('old');
  111.   isBoth && verList.push('both');
  112.   isUncached && verList.push('nocache');
  113.   for (let envNum = 0; envNum < envList.length; envNum++) {
  114.     for (let verNum = 0; verNum < verList.length; verNum++) {
  115.       let env = envList[envNum];
  116.       let ver = verList[verNum];
  117.       let assets = [assetList['main'], assetList[env]];
  118.       let patterns = [];
  119.       let outputFile = filenameTemplate.replace('{env}', env).replace('{ver}', ver);
  120.       (ver === 'dep' || ver === 'both') && patterns.push(patternList['dep']);
  121.       (ver === 'old' || ver === 'both') && patterns.push(patternList['old']);
  122.       generateServiceWorker(env, ver, assets, patterns, outputPath, outputFile);
  123.     }
  124.   }
  125. }
  126.  
  127. /**
  128.  * Generates a single Service Worker.
  129.  * @param {string} environment  Expected 'dev', 'stg', or 'Prod'
  130.  * @param {string} version  Expected 'dep', 'old', 'both', or 'nocache'
  131.  * @param {Array}  assets  One or more strings with partial blueprint files
  132.  * @param {Array}  patterns  Zero or more strings with precache file search patterns
  133.  * @param {string}  outputPath  Directory where to create the service worker script
  134.  * @returns {void}
  135.  */
  136. function generateServiceWorker(environment, version, assets, patterns, outputPath, outputFile) {
  137.   const tempBlueprintFile = path.resolve(SCRIPT_PATH, `temp-blueprint-${outputFile}`);
  138.   const swFile = path.resolve(outputPath, outputFile);
  139.   createBlueprint(assets[0], assets[1], tempBlueprintFile)
  140.     .then(() => workboxBuild.injectManifest({
  141.       swSrc: tempBlueprintFile,
  142.       swDest: swFile,
  143.       globDirectory: path.resolve(ROOT_PATH, 'cartridges'),
  144.       globPatterns: patterns,
  145.       globIgnores: ['**/critical.css'],
  146.       manifestTransforms: [
  147.         addPlaceholderPrefix,
  148.         addOfflinePages
  149.       ]
  150.     }))
  151.     .then(({count, size, warnings}) => {
  152.       warnings.forEach((warn) => {
  153.         console.warn(`${outputFile}:`, warn);
  154.       });
  155.       console.log(`${outputFile}: Included ${count} files for precache` + (!isNaN(size) ? ` (total ${size} bytes).` : ''));
  156.     })
  157.     .catch((e) => {
  158.       console.error(`Error generating ${outputFile}:`, e);
  159.       return Promise.resolve();
  160.     })
  161.     .then(() => {
  162.       removeBlueprint(tempBlueprintFile)
  163.         .catch((e) => {
  164.           console.warn(`Could not delete ${tempBlueprintFile}. Please remove it manually.`);
  165.         });
  166.     });
  167. }
  168.  
  169. /**
  170.  * Creates a complete blueprint file (concatenates two partial blueprints into a temporary file)
  171.  * @param {string} mainFile  The master partial blueprint
  172.  * @param {string} additionalFile  The environment-dependent partial blueprint
  173.  * @param {string} targetFile  The destination temporary file
  174.  * @returns {Promise}  Resolved without a value or rejected with an error
  175.  */
  176. function createBlueprint(mainFile, additionalFile, targetFile) {
  177.   return new Promise(function(resolve, reject) {
  178.     fs.copyFile(mainFile, targetFile, (e) => {
  179.       if (e) {
  180.         reject(e);
  181.       } else {
  182.         fs.readFile(additionalFile, (e, data) => {
  183.           if (e) {
  184.             reject(e);
  185.           } else {
  186.             fs.appendFile(targetFile, '\n\n' + data, 'utf8', (e) => {
  187.               if (e) {
  188.                 reject(e);
  189.               } else {
  190.                 resolve();
  191.               }
  192.             });
  193.           }
  194.         });
  195.       }
  196.     });
  197.   });
  198. }
  199.  
  200. /**
  201.  * Deletes the temporary blueprint file
  202.  * @param {string} targetFile  The temporary file
  203.  * @returns {Promise}  Resolved without a value or rejected with an error
  204.  */
  205. function removeBlueprint(targetFile) {
  206.   return new Promise(function(resolve, reject) {
  207.     fs.unlink(targetFile, (e) => {
  208.       if (e) {
  209.         reject(e);
  210.       } else {
  211.         resolve();
  212.       }
  213.     });
  214.     resolve();
  215.   });
  216. }
  217.  
  218. /**
  219.  * Removes "/.../default/" and "/v1523459585" from workbox manifest entries.
  220.  * @param {array} originalEntries  The manifest's precache list
  221.  * @returns {object}  Object with the modified precache entries and list of warnings
  222.  */
  223. function addPlaceholderPrefix(originalEntries) {
  224.   const entries = originalEntries.map((originalEntry) => {
  225.     const entry = Object.assign({}, originalEntry);
  226.     entry.url = entry.url
  227.       .replace(/(^.+\/default\/)/gi, '') // Remove the base path "/.../default/"
  228.       .replace(/\/v\d+/gi, ''); // Remove the "/v1523459585/" (DMW versioning) part
  229.     return entry;
  230.   });
  231.   return {
  232.     manifest: entries,
  233.     warnings: []
  234.   };
  235. }
  236.  
  237. /**
  238.  * Adds "/offline.html" for precaching to workbox manifest entries
  239.  * @param {array} originalEntries  The manifest's precache list
  240.  * @returns {object}  Object with the modified precache entries and list of warnings
  241.  */
  242. function addOfflinePages(originalEntries) {
  243.   const entries = originalEntries.slice();
  244.   entries.push({
  245.     'url': '/offline.html',
  246.     'revision': 'v111111111111111111111111111111'
  247.   });
  248.   return {
  249.     manifest: entries,
  250.     warnings: []
  251.   };
  252. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement