From bb790eaea44e6966d22bb1b8f6ef7bcf23a17dd6 Mon Sep 17 00:00:00 2001 From: Salome DO Date: Fri, 13 Oct 2023 17:26:07 +0200 Subject: [PATCH] feat: prefetch dynamic content --- .gitignore | 2 +- examples/my-ngsw-app/package-lock.json | 2 +- examples/my-ngsw-app/package.json | 2 +- src/index.ts | 3 ++- src/schema.json | 7 ++++++- src/schema.ts | 5 ++++- src/templates/prefetch.mustache | 27 +++++++++++++++++++++++--- 7 files changed, 39 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 943af752..0125458e 100644 --- a/.gitignore +++ b/.gitignore @@ -115,4 +115,4 @@ dist .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* diff --git a/examples/my-ngsw-app/package-lock.json b/examples/my-ngsw-app/package-lock.json index d7b201c3..6a2b016a 100644 --- a/examples/my-ngsw-app/package-lock.json +++ b/examples/my-ngsw-app/package-lock.json @@ -53,6 +53,7 @@ "dependencies": { "@angular-devkit/architect": "^0.1602.0", "@angular-devkit/core": "^16.2.0", + "mustache": "^4.2.0", "typescript": "~5.1.6", "webpack": "^5.79.0" }, @@ -66,7 +67,6 @@ "copyfiles": "^2.4.1", "eslint": "^8.30.0", "jest": "^29.3.1", - "mustache": "^4.2.0", "rimraf": "^5.0.0", "ts-jest": "^29.0.3" } diff --git a/examples/my-ngsw-app/package.json b/examples/my-ngsw-app/package.json index e47737a9..8f527626 100644 --- a/examples/my-ngsw-app/package.json +++ b/examples/my-ngsw-app/package.json @@ -6,7 +6,7 @@ "start": "ng serve", "start:prod": "npm run build:prod && npm run server", "start:prod:ci": "npm run build:prod && npm run server:ci", - "server": "http-server -p 8080 -c-1 dist", + "server": "http-server -p 8080 -c-1 dist --cors", "server:ci": "nohup http-server -p 8080 -c-1 dist &", "build": "ng build", "build:prod": "npm run clean && ng build --configuration production && npm run generate:prefetch", diff --git a/src/index.ts b/src/index.ts index 5d1d0479..3dc251a0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -97,7 +97,8 @@ export default createBuilder(async (options, context): Pr const variables = { resourceArray: JSON.stringify(resourceArray), prefetchConfig: JSON.stringify(filterOptions(options, configOptions)), - staticsFullPath: options.staticsFullPath + staticsFullPath: options.staticsFullPath, + localizationPattern: options.localizationPattern }; const prefetchJs = Mustache.render(prefetchTemplate, variables); diff --git a/src/schema.json b/src/schema.json index 33ccfa2f..f7605310 100644 --- a/src/schema.json +++ b/src/schema.json @@ -32,8 +32,13 @@ }, "staticsFullPath": { "type": "string", - "description": "By default the prefetched resources are hosted next to the `ngxPrefetch.js` file, on the same server. If it is not the case, you can configure the full path of the resources that will be prefetched. It is also possible to set this value by runtime. Instead of setting it in the Builder's options, you can search and replace for `{STATICS_FULL_PATH}` on the server side in order to inject a path.", + "description": "By default the prefetched static resources are hosted next to the `ngxPrefetch.js` file, on the same server. If it is not the case, you can configure the full path of the static resources that will be prefetched. It is also possible to set this value at runtime. Instead of setting it in the Builder's options, you can search for `{STATICS_FULL_PATH}` and replace it on the server side in order to inject a path.", "default": "{STATICS_FULL_PATH}" + }, + "localizationPattern": { + "type": "string", + "description": "Pattern for the path of the localization file. By default, the pattern corresponds to the JSON file in a folder called localizations.", + "default": "/localizations/${language}.json" } }, "additionalProperties": false, diff --git a/src/schema.ts b/src/schema.ts index 3c6bcfb2..14fca883 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -14,6 +14,9 @@ export interface PrefetchBuilderSchema extends JsonObject { /** Flag for creating a production (minified) version of the js file or a development one. */ production: boolean; - /** By default the prefetched resources are hosted next to the `ngxPrefetch.js` file, on the same server. If it is not the case, you can configure the full path of the resources that will be prefetched. It is also possible to set this value by runtime. Instead of setting it in the Builder's options, you can search and replace for `{STATICS_FULL_PATH}` on the server side in order to inject a path. */ + /** By default the prefetched static resources are hosted next to the `ngxPrefetch.js` file, on the same server. If it is not the case, you can configure the full path of the static resources that will be prefetched. It is also possible to set this value at runtime. Instead of setting it in the Builder's options, you can search for `{STATICS_FULL_PATH}` and replace it on the server side in order to inject a path. */ staticsFullPath: string; + + /** Pattern for the path of the localization file. By default, the pattern corresponds to the JSON file in a folder called localizations. */ + localizationPattern: string; } diff --git a/src/templates/prefetch.mustache b/src/templates/prefetch.mustache index a1dc92d0..b587ca88 100644 --- a/src/templates/prefetch.mustache +++ b/src/templates/prefetch.mustache @@ -23,19 +23,40 @@ } var resList = {{{resourceArray}}}; - var fullPath = '{{{staticsFullPath}}}'; + var staticsFullPath = '{{{staticsFullPath}}}'; var staticsFullPathKey = 'STATICS_FULL_PATH'; // for testing - if (fullPath === `{${staticsFullPathKey}}`) { fullPath = '.'; } + if (staticsFullPath === `{${staticsFullPathKey}}`) { staticsFullPath = '.'; } var language = '{LANG}'; var languageKey = 'LANG'; + var locPattern = `{{{localizationPattern}}}`; if (language !== `{${languageKey}}`) { - resList.push(`/localizations/${language}.json`); + resList.push(locPattern); + } + + var dynamicContentPath = '{DYNAMIC_CONTENT_PATH}'; + var dynamicContentPathKey = 'DYNAMIC_CONTENT_PATH'; + + var dynamicContentFiles = '{DYNAMIC_CONTENT_FILES}'; + var dynamicContentFilesKey = 'DYNAMIC_CONTENT_FILES'; + + var hasDynamicContent = (dynamicContentPath !== `{${dynamicContentPathKey}}`) && (dynamicContentFiles !== `{${dynamicContentFilesKey}}`); + + if (hasDynamicContent) { + try { + dynamicContentFiles = JSON.parse(dynamicContentFiles); + } catch (e) { + console.error(`Could not parse dynamic content files: '${dynamicContentFiles}'`); + } } resList.forEach(function(resource) { if (typeof resource === 'string') { + var fullPath = staticsFullPath; + if (hasDynamicContent && dynamicContentFiles.includes(resource.slice(1))) { + fullPath = dynamicContentPath + '/'; + } var splitRes = resource.split('.'); var extension = splitRes[splitRes.length - 1]; appendLink(fullPath + resource, getResType(extension));