cdn-resources-service.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. const { URL } = require('url');
  2. const urljoin = require('url-join');
  3. const helpers = require('@commons/util/helpers');
  4. const { envUtils } = require('growi-commons');
  5. const cdnLocalScriptRoot = 'public/js/cdn';
  6. const cdnLocalScriptWebRoot = '/js/cdn';
  7. const cdnLocalStyleRoot = 'public/styles/cdn';
  8. const cdnLocalStyleWebRoot = '/styles/cdn';
  9. class CdnResourcesService {
  10. constructor() {
  11. this.logger = require('@alias/logger')('growi:service:CdnResourcesService');
  12. this.loadManifests();
  13. }
  14. get noCdn() {
  15. return envUtils.toBoolean(process.env.NO_CDN);
  16. }
  17. loadManifests() {
  18. this.cdnManifests = require('@root/resource/cdn-manifests');
  19. this.logger.debug('manifest data loaded : ', this.cdnManifests);
  20. }
  21. getScriptManifestByName(name) {
  22. const manifests = this.cdnManifests.js
  23. .filter((manifest) => { return manifest.name === name });
  24. return (manifests.length > 0) ? manifests[0] : null;
  25. }
  26. getStyleManifestByName(name) {
  27. const manifests = this.cdnManifests.style
  28. .filter((manifest) => { return manifest.name === name });
  29. return (manifests.length > 0) ? manifests[0] : null;
  30. }
  31. /**
  32. * download all resources from CDN and write to FS
  33. *
  34. * !! This method should be invoked only by /bin/download-cdn-resources when build client !!
  35. *
  36. * @param {CdnResourceDownloader} cdnResourceDownloader
  37. */
  38. async downloadAndWriteAll(cdnResourceDownloader) {
  39. const CdnResource = require('@commons/models/cdn-resource');
  40. const cdnScriptResources = this.cdnManifests.js.map((manifest) => {
  41. const outDir = helpers.root(cdnLocalScriptRoot);
  42. return new CdnResource(manifest.name, manifest.url, outDir);
  43. });
  44. const cdnStyleResources = this.cdnManifests.style.map((manifest) => {
  45. const outDir = helpers.root(cdnLocalStyleRoot);
  46. return new CdnResource(manifest.name, manifest.url, outDir);
  47. });
  48. const dlStylesOptions = {
  49. replaceUrl: {
  50. webroot: cdnLocalStyleWebRoot,
  51. },
  52. };
  53. return Promise.all([
  54. cdnResourceDownloader.downloadScripts(cdnScriptResources),
  55. cdnResourceDownloader.downloadStyles(cdnStyleResources, dlStylesOptions),
  56. ]);
  57. }
  58. /**
  59. * Generate script tag string
  60. *
  61. * @param {Object} manifest
  62. */
  63. generateScriptTag(manifest) {
  64. const attrs = [];
  65. const args = manifest.args || {};
  66. if (args.async) {
  67. attrs.push('async');
  68. }
  69. if (args.defer) {
  70. attrs.push('defer');
  71. }
  72. // TODO process integrity
  73. const url = this.noCdn
  74. ? `${urljoin(cdnLocalScriptWebRoot, manifest.name)}.js`
  75. : manifest.url;
  76. return `<script src="${url}" ${attrs.join(' ')}></script>`;
  77. }
  78. getScriptTagByName(name) {
  79. const manifest = this.getScriptManifestByName(name);
  80. return this.generateScriptTag(manifest);
  81. }
  82. getScriptTagsByGroup(group) {
  83. return this.cdnManifests.js
  84. .filter((manifest) => {
  85. return manifest.groups != null && manifest.groups.includes(group);
  86. })
  87. .map((manifest) => {
  88. return this.generateScriptTag(manifest);
  89. });
  90. }
  91. /**
  92. * Generate style tag string
  93. *
  94. * @param {Object} manifest
  95. */
  96. generateStyleTag(manifest) {
  97. const attrs = [];
  98. const args = manifest.args || {};
  99. if (args.async) {
  100. attrs.push('async');
  101. }
  102. if (args.defer) {
  103. attrs.push('defer');
  104. }
  105. // TODO process integrity
  106. const url = this.noCdn
  107. ? `${urljoin(cdnLocalStyleWebRoot, manifest.name)}.css`
  108. : manifest.url;
  109. return `<link rel="stylesheet" href="${url}" ${attrs.join(' ')}>`;
  110. }
  111. getStyleTagByName(name) {
  112. const manifest = this.getStyleManifestByName(name);
  113. return this.generateStyleTag(manifest);
  114. }
  115. getStyleTagsByGroup(group) {
  116. return this.cdnManifests.style
  117. .filter((manifest) => {
  118. return manifest.groups != null && manifest.groups.includes(group);
  119. })
  120. .map((manifest) => {
  121. return this.generateStyleTag(manifest);
  122. });
  123. }
  124. getHighlightJsStyleTag(styleName) {
  125. let manifest = this.getStyleManifestByName('highlight-theme-github');
  126. // replace style
  127. if (!this.noCdn) {
  128. const url = new URL(`${styleName}.css`, manifest.url); // resolve `${styleName}.css` from manifest.url
  129. // clone manifest
  130. manifest = Object.assign(manifest, { url: url.toString() });
  131. }
  132. return this.generateStyleTag(manifest);
  133. }
  134. }
  135. module.exports = CdnResourcesService;