1
0

index.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { load as loadYaml } from 'js-yaml'
  2. import fs from 'node:fs'
  3. import path from 'node:path'
  4. import { PluginOption, loadEnv } from 'vite'
  5. // we need to use relative import from atlas-meta-server because of an issue in Vite: https://github.com/vitejs/vite/issues/5370
  6. import { generateCommonMetaTags } from '../../atlas-meta-server/src/tags'
  7. import { generateMetaHtml } from '../../atlas-meta-server/src/utils'
  8. import { configSchema } from '../src/config/configSchema'
  9. // read config file - we cannot use `@/config` since it relies on YAML plugin being already loaded and that's not done in this context
  10. const rawConfigPath = path.resolve(__dirname, '..', 'atlas.config.yml')
  11. const rawConfigText = fs.readFileSync(rawConfigPath, 'utf-8')
  12. const rawConfig = loadYaml(rawConfigText)
  13. const parsedConfig = configSchema.parse(rawConfig)
  14. // This plugin fixes https://github.com/Joystream/atlas/issues/3005
  15. // By default vite was transpiling `import.meta.url` (that you can find in `node_modules/@polkadot/api/packageInfo.js`)
  16. // to the code which uses `document.baseURI`. `Document` is not available in workers and in the result we got reference errors.
  17. // This plugin replace `document.baseURI` with `self.location.href` which should be available in the worker
  18. export const PolkadotWorkerMetaFixPlugin: PluginOption = {
  19. name: 'resolve-import-meta-polkadot',
  20. resolveImportMeta(_, { chunkId }) {
  21. if (chunkId.includes('polkadot-worker')) {
  22. return 'self.location.href'
  23. }
  24. },
  25. }
  26. // This plugin overrides the name property in manifest.webmanifest file
  27. export const AtlasWebmanifestPlugin: PluginOption = {
  28. name: 'atlas-webmanifest',
  29. buildStart() {
  30. const inputManifestPath = path.resolve('src/public/manifest.webmanifest')
  31. const manifestData = JSON.parse(fs.readFileSync(inputManifestPath, `utf-8`))
  32. Object.assign(manifestData, {
  33. name: parsedConfig.general.appName,
  34. })
  35. try {
  36. this.emitFile({
  37. type: 'asset',
  38. source: JSON.stringify(manifestData, null, 2),
  39. fileName: path.normalize('manifest.webmanifest'),
  40. })
  41. } catch (err) {
  42. throw new Error('Failed to emit asset file, possibly a naming conflict?')
  43. }
  44. },
  45. }
  46. // This plugin replaces <meta-tags /> in index.html with the actual meta tags
  47. export const AtlasHtmlMetaTagsPlugin: PluginOption = {
  48. name: 'atlas-html-meta-tags',
  49. transformIndexHtml: {
  50. enforce: 'pre',
  51. transform: (html: string) => {
  52. const metaTags = generateCommonMetaTags(
  53. parsedConfig.general.appName,
  54. parsedConfig.general.appUrl,
  55. parsedConfig.general.appName,
  56. parsedConfig.general.appDescription,
  57. parsedConfig.general.appOgImgPath,
  58. parsedConfig.general.appTwitterId
  59. )
  60. const titleHtml = `<title>${parsedConfig.general.appName}</title>`
  61. const metaHtml = generateMetaHtml(metaTags, true)
  62. // include link to Orion GraphQL API so that atlas-meta-server can use it to fetch data for content previews
  63. const orionUrlEnvKey = 'VITE_PRODUCTION_ORION_URL'
  64. const orionUrl =
  65. process.env[orionUrlEnvKey] || loadEnv('production', path.join(process.cwd(), 'src'))[orionUrlEnvKey]
  66. const generateMetaTagHtml = (name: string, content: string) =>
  67. `<meta name="${name}" property="${name}" content="${content}">`
  68. const orionMetaHtml = generateMetaTagHtml('atlas:orion_url', orionUrl)
  69. const yppOgTitleMetaHtml =
  70. parsedConfig.features.ypp.landingPageOgTitle &&
  71. generateMetaTagHtml('atlas:ypp_og_title', parsedConfig.features.ypp.landingPageOgTitle)
  72. const yppOgDescriptionMetaHtml =
  73. parsedConfig.features.ypp.landingPageOgDescription &&
  74. generateMetaTagHtml('atlas:ypp_og_description', parsedConfig.features.ypp.landingPageOgDescription)
  75. const yppOgImageMetaHtml =
  76. parsedConfig.features.ypp.landingPageOgImgPath &&
  77. generateMetaTagHtml('atlas:ypp_og_image', parsedConfig.features.ypp.landingPageOgImgPath)
  78. const finalMetaHtml = [
  79. titleHtml,
  80. metaHtml,
  81. orionMetaHtml,
  82. yppOgTitleMetaHtml,
  83. yppOgDescriptionMetaHtml,
  84. yppOgImageMetaHtml,
  85. ]
  86. .filter((v) => v)
  87. .join('\n')
  88. return html.replace('<meta-tags />', finalMetaHtml)
  89. },
  90. },
  91. }
  92. // This plugin enables /embedded path in development mode.
  93. // Without this, dev server will always try to serve main index.html file
  94. export const EmbeddedFallbackPlugin: PluginOption = {
  95. name: 'embedded-fallback',
  96. configureServer(server) {
  97. server.middlewares.use('/embedded', (req, res, next) => {
  98. if (req.url?.includes('.')) {
  99. next()
  100. return
  101. }
  102. req.url = '/index.html'
  103. req.originalUrl = '/embedded/index.html'
  104. next()
  105. })
  106. },
  107. }
  108. export const OptimizePlugin: PluginOption = {
  109. name: 'optimize-init-plugin',
  110. transformIndexHtml: {
  111. enforce: 'pre',
  112. transform: (html) => {
  113. const optimizeEnv = 'VITE_OPTIMIZE_ID'
  114. const optimizeId = process.env[optimizeEnv] || loadEnv('production', path.join(process.cwd(), 'src'))[optimizeEnv]
  115. const optimizeScript = optimizeId
  116. ? `<script src="https://www.googleoptimize.com/optimize.js?id=${optimizeId}"></script>`
  117. : ''
  118. return html.replace('<optimize-script />', optimizeScript)
  119. },
  120. },
  121. }