appConfig.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import colors from 'picocolors';
  2. import { readPackageJSON } from 'pkg-types';
  3. import { type PluginOption } from 'vite';
  4. import { getEnvConfig } from '../utils/env';
  5. import { createContentHash } from '../utils/hash';
  6. const GLOBAL_CONFIG_FILE_NAME = '_app.config.js';
  7. const PLUGIN_NAME = 'app-config';
  8. async function createAppConfigPlugin({
  9. root,
  10. isBuild,
  11. }: {
  12. root: string;
  13. isBuild: boolean;
  14. }): Promise<PluginOption> {
  15. let publicPath: string;
  16. let source: string;
  17. if (!isBuild) {
  18. return {
  19. name: PLUGIN_NAME,
  20. };
  21. }
  22. const { version = '' } = await readPackageJSON(root);
  23. return {
  24. name: PLUGIN_NAME,
  25. async configResolved(_config) {
  26. let appTitle = _config?.env?.VITE_GLOB_APP_TITLE ?? '';
  27. appTitle = appTitle.replace(/\s/g, '_');
  28. publicPath = _config.base;
  29. source = await getConfigSource(appTitle);
  30. },
  31. async transformIndexHtml(html) {
  32. publicPath = publicPath.endsWith('/') ? publicPath : `${publicPath}/`;
  33. const appConfigSrc = `${
  34. publicPath || '/'
  35. }${GLOBAL_CONFIG_FILE_NAME}?v=${version}-${createContentHash(source)}}`;
  36. return {
  37. html,
  38. tags: [
  39. {
  40. tag: 'script',
  41. attrs: {
  42. src: appConfigSrc,
  43. },
  44. },
  45. ],
  46. };
  47. },
  48. async generateBundle() {
  49. try {
  50. this.emitFile({
  51. type: 'asset',
  52. fileName: GLOBAL_CONFIG_FILE_NAME,
  53. source,
  54. });
  55. console.log(colors.cyan(`✨configuration file is build successfully!`));
  56. } catch (error) {
  57. console.log(
  58. colors.red('configuration file configuration file failed to package:\n' + error),
  59. );
  60. }
  61. },
  62. };
  63. }
  64. /**
  65. * Get the configuration file variable name
  66. * @param env
  67. */
  68. const getVariableName = (title: string) => {
  69. return `__PRODUCTION__${title || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, '');
  70. };
  71. async function getConfigSource(appTitle: string) {
  72. const config = await getEnvConfig();
  73. const variableName = getVariableName(appTitle);
  74. const windowVariable = `window.${variableName}`;
  75. // Ensure that the variable will not be modified
  76. let source = `${windowVariable}=${JSON.stringify(config)};`;
  77. source += `
  78. Object.freeze(${windowVariable});
  79. Object.defineProperty(window, "${variableName}", {
  80. configurable: false,
  81. writable: false,
  82. });
  83. `.replace(/\s/g, '');
  84. return source;
  85. }
  86. export { createAppConfigPlugin };