cdn-resources-service.js 4.3 KB

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