@open-xchange/vite-plugin-ox-manifests 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/index.d.ts +56 -0
  3. package/dist/index.js +175 -0
  4. package/dist/plugins/gettext.d.ts +2 -0
  5. package/dist/plugins/gettext.js +63 -0
  6. package/dist/plugins/manifests.d.ts +2 -0
  7. package/dist/plugins/manifests.js +132 -0
  8. package/dist/plugins/meta.d.ts +2 -0
  9. package/dist/plugins/meta.js +21 -0
  10. package/dist/plugins/plugin.d.ts +24 -0
  11. package/dist/plugins/plugin.js +6 -0
  12. package/dist/plugins/relative-paths.d.ts +2 -0
  13. package/dist/plugins/relative-paths.js +9 -0
  14. package/dist/plugins/serve.d.ts +2 -0
  15. package/dist/plugins/serve.js +66 -0
  16. package/dist/plugins/settings.d.ts +2 -0
  17. package/dist/plugins/settings.js +141 -0
  18. package/dist/util.d.ts +11 -0
  19. package/dist/util.js +77 -0
  20. package/package.json +24 -22
  21. package/.eslintrc.cjs +0 -10
  22. package/.gitlab-ci.yml +0 -26
  23. package/index.js +0 -172
  24. package/src/constants.js +0 -1
  25. package/src/plugins/gettext.js +0 -69
  26. package/src/plugins/manifests.js +0 -136
  27. package/src/plugins/meta.js +0 -13
  28. package/src/plugins/relative-paths.js +0 -7
  29. package/src/plugins/serve.js +0 -64
  30. package/src/plugins/settings.js +0 -147
  31. package/src/util.js +0 -61
  32. package/test/.eslintrc.cjs +0 -5
  33. package/test/deps/main.test.js +0 -32
  34. package/test/gettext-chunked/another_chunk.js +0 -4
  35. package/test/gettext-chunked/i18n/de_DE.po +0 -16
  36. package/test/gettext-chunked/i18n/en_US.po +0 -16
  37. package/test/gettext-chunked/main.test.js +0 -67
  38. package/test/gettext-chunked/manifest.json +0 -3
  39. package/test/gettext-chunked/register.js +0 -6
  40. package/test/gettext-multiple/i18n/de_DE.po +0 -22
  41. package/test/gettext-multiple/i18n/en_US.po +0 -22
  42. package/test/gettext-multiple/main.test.js +0 -71
  43. package/test/gettext-multiple/manifest.json +0 -3
  44. package/test/gettext-multiple/register.js +0 -4
  45. package/test/gettext-simple/i18n/de_DE.po +0 -18
  46. package/test/gettext-simple/i18n/en_US.po +0 -18
  47. package/test/gettext-simple/main.test.js +0 -61
  48. package/test/gettext-simple/manifest.json +0 -3
  49. package/test/gettext-simple/register.js +0 -3
  50. package/test/hmr/main.test.js +0 -121
  51. package/test/hmr/manifest.json +0 -3
  52. package/test/hmr/register.js +0 -1
  53. package/test/hmr/settings.js +0 -3
  54. package/test/html-relative-paths/index.html +0 -7
  55. package/test/html-relative-paths/index.js +0 -3
  56. package/test/html-relative-paths/main.test.js +0 -39
  57. package/test/html-relative-paths/other.html +0 -7
  58. package/test/html-relative-paths/style.css +0 -1
  59. package/test/manifest-dependencies/main.test.js +0 -26
  60. package/test/manifest-dependencies/manifest.json +0 -3
  61. package/test/manifest-dependencies/register.js +0 -3
  62. package/test/manifest-dependencies/style.less +0 -1
  63. package/test/manifest-dynamic-deps/main.test.js +0 -28
  64. package/test/manifest-dynamic-deps/manifest.json +0 -3
  65. package/test/manifest-dynamic-deps/register.js +0 -7
  66. package/test/manifest-dynamic-deps/some_dep.js +0 -5
  67. package/test/manifest-dynamic-deps/style.less +0 -1
  68. package/test/manifest-multiple/entry1.js +0 -1
  69. package/test/manifest-multiple/main.test.js +0 -83
  70. package/test/manifest-multiple/manifest.json +0 -7
  71. package/test/manifest-multiple/sub/entry2.js +0 -3
  72. package/test/manifest-multiple/sub/manifest.json +0 -4
  73. package/test/manifest-simple/main.test.js +0 -105
  74. package/test/manifest-simple/manifest.json +0 -3
  75. package/test/manifest-simple/register.js +0 -1
  76. package/test/meta/main.test.js +0 -25
  77. package/test/meta/manifest.json +0 -3
  78. package/test/meta/register.js +0 -1
  79. package/test/preload-helper-bundled/async.js +0 -1
  80. package/test/preload-helper-bundled/index.js +0 -1
  81. package/test/preload-helper-bundled/main.test.js +0 -32
  82. package/test/preload-helper-bundled/manifest.json +0 -4
  83. package/test/preload-helper-separate/bar.js +0 -1
  84. package/test/preload-helper-separate/foo.js +0 -3
  85. package/test/preload-helper-separate/index.js +0 -1
  86. package/test/preload-helper-separate/main.test.js +0 -34
  87. package/test/preload-helper-separate/manifest.json +0 -4
  88. package/test/settings-core/index.js +0 -4
  89. package/test/settings-core/main.test.js +0 -56
  90. package/test/settings-core/manifest.json +0 -4
  91. package/test/settings-core/no-settings.js +0 -3
  92. package/test/settings-core/settings.js +0 -3
  93. package/test/settings-external/index.js +0 -3
  94. package/test/settings-external/main.test.js +0 -61
  95. package/test/settings-external/manifest.json +0 -4
  96. package/test/settings-external/settings.js +0 -3
  97. package/test/settings-ts/index.js +0 -3
  98. package/test/settings-ts/main.test.js +0 -30
  99. package/test/settings-ts/manifest.json +0 -4
  100. package/test/settings-ts/settings.ts +0 -4
  101. package/test/settings-with-requirements/foo.js +0 -3
  102. package/test/settings-with-requirements/forth-settings.js +0 -3
  103. package/test/settings-with-requirements/index.js +0 -5
  104. package/test/settings-with-requirements/main.test.js +0 -95
  105. package/test/settings-with-requirements/manifest.json +0 -12
  106. package/test/settings-with-requirements/other-settings.js +0 -3
  107. package/test/settings-with-requirements/other.js +0 -4
  108. package/test/settings-with-requirements/settings.js +0 -3
  109. package/test/settings-with-requirements/third-settings.js +0 -3
  110. package/test/util/deep-merge.test.js +0 -59
  111. package/test/util.js +0 -16
package/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.6.0] - 2023-05-16
8
+
9
+ ### Changed
10
+
11
+ - Convert source code to TypeScript [`029a4c7`](https://gitlab.open-xchange.com/frontend/vite-plugin-ox-manifests/commit/029a4c75c96483a221a54fc54589467b1a77eead)
12
+
13
+ ### Removed
14
+
15
+ - Coverage files from npm package [`11fc7a8`](https://gitlab.open-xchange.com/frontend/vite-plugin-ox-manifests/commit/11fc7a8ba825f1a3bf1913b0134b57b1d1029f99)
16
+
17
+
18
+ ## [0.5.4] - 2023-03-17
19
+
20
+ ### Removed
21
+
22
+ - Test files from npm package [`9d76062`](https://gitlab.open-xchange.com/frontend/vite-plugin-ox-manifests/commit/9d760623362bcbbb7e52fd551a0693cc43c61ed5)
23
+
24
+
25
+ ## [0.5.3] - 2023-03-17
26
+
27
+ ### Added
28
+
29
+ - Add @open-xchange/lint [`c5ac8b6`](https://gitlab.open-xchange.com/frontend/vite-plugin-ox-manifests/commit/c5ac8b6009c8c035a2c609a2368a7ccfd422e65a)
30
+
31
+
32
+ ## [0.5.2] - 2022-12-13
33
+
34
+ - Start Changelog
35
+
36
+ [unreleased]: https://gitlab.open-xchange.com/frontend/vite-plugin-ox-manifests/compare/0.6.0...main
37
+ [0.6.0]: https://gitlab.open-xchange.com/frontend/vite-plugin-ox-manifests/compare/0.5.4...0.6.0
38
+ [0.5.4]: https://gitlab.open-xchange.com/frontend/vite-plugin-ox-manifests/compare/0.5.3...0.5.4
39
+ [0.5.3]: https://gitlab.open-xchange.com/frontend/vite-plugin-ox-manifests/compare/0.5.2...0.5.3
@@ -0,0 +1,56 @@
1
+ import type { Plugin } from 'vite';
2
+ import { mergeManifests } from './util';
3
+ export { mergeManifests };
4
+ export interface OxManifest {
5
+ namespace: string;
6
+ path: string;
7
+ requires?: string;
8
+ raw?: string;
9
+ generator?: string;
10
+ }
11
+ /**
12
+ * Configuration options for the Vite plugin "vite-plugin-ox-manifests".
13
+ */
14
+ export interface VitePluginOxManifestsOptions {
15
+ /**
16
+ * If set to `true`, this plugin will watch manifest changes and reload the
17
+ * UI. Default value is `false`.
18
+ */
19
+ watch?: boolean;
20
+ /**
21
+ * Convenience method to specify additional entry points for the production
22
+ * build. Can be specified as a glob-pattern.
23
+ */
24
+ entryPoints?: string;
25
+ /**
26
+ * Specifies, that every path in a manifest is used as an entry-point for the
27
+ * production build. Default is `true`!
28
+ */
29
+ manifestsAsEntryPoints?: boolean;
30
+ /**
31
+ * If disabled, settings will not be automatically detected and therefore
32
+ * have to provide a manual manifest.json. Default is `true`!
33
+ */
34
+ autoloadSettings?: boolean;
35
+ /**
36
+ * An array of valid file-extensions for entry points. Default is
37
+ * `['js', 'mjs', 'ts']`.
38
+ */
39
+ supportedEntryExtensions?: string[];
40
+ /**
41
+ * An object that will be translated into a `meta.json` file in the root
42
+ * directory.
43
+ */
44
+ meta?: object | null;
45
+ }
46
+ /**
47
+ * Type shape of the Vite plugin "vite-plugin-ox-manifests".
48
+ */
49
+ export interface VitePluginOxManifests extends Plugin {
50
+ getManifests(): Promise<OxManifest[]>;
51
+ }
52
+ export declare const PROJECT_NAME = "@open-xchange/vite-plugin-ox-manifests";
53
+ /**
54
+ * Creates a vite-plugin to include manifests in dev and production mode
55
+ */
56
+ export default function pluginOxManifests(options?: VitePluginOxManifestsOptions): VitePluginOxManifests;
package/dist/index.js ADDED
@@ -0,0 +1,175 @@
1
+ import { deepMergeObject, mergeManifests } from './util';
2
+ import manifestsPlugin from './plugins/manifests';
3
+ import relativePathsPlugin from './plugins/relative-paths';
4
+ import settingsPlugin from './plugins/settings';
5
+ import servePlugin from './plugins/serve';
6
+ import gettextPlugin from './plugins/gettext';
7
+ import metaPlugin from './plugins/meta';
8
+ export { mergeManifests };
9
+ export const PROJECT_NAME = '@open-xchange/vite-plugin-ox-manifests';
10
+ /**
11
+ * Creates a vite-plugin to include manifests in dev and production mode
12
+ */
13
+ export default function pluginOxManifests(options) {
14
+ const resolvedOptions = {
15
+ watch: false,
16
+ entryPoints: '',
17
+ manifestsAsEntryPoints: true,
18
+ autoloadSettings: true,
19
+ supportedEntryExtensions: ['js', 'mjs', 'ts'],
20
+ meta: null,
21
+ ...options
22
+ };
23
+ let resolvedConfig;
24
+ const plugins = [
25
+ // add settings first
26
+ settingsPlugin(resolvedOptions),
27
+ relativePathsPlugin(resolvedOptions),
28
+ servePlugin(resolvedOptions),
29
+ gettextPlugin(resolvedOptions),
30
+ metaPlugin(resolvedOptions),
31
+ // manifest plugin last
32
+ manifestsPlugin(resolvedOptions)
33
+ ];
34
+ const pluginManifests = {
35
+ name: PROJECT_NAME,
36
+ enforce: 'post',
37
+ async config(config, env) {
38
+ for (const plugin of plugins) {
39
+ plugin.pluginResolved?.(pluginManifests);
40
+ if (typeof plugin.config === 'function') {
41
+ config = (await plugin.config.call(this, config, env)) || config;
42
+ }
43
+ else if (plugin.config) {
44
+ throw new TypeError(`object hooks not supported, specify function callback (${plugin.name}.config)`);
45
+ }
46
+ }
47
+ return config;
48
+ },
49
+ async getManifests() {
50
+ const manifests = [];
51
+ for (const plugin of plugins) {
52
+ if (plugin.getManifests) {
53
+ const result = await plugin.getManifests.call(this);
54
+ manifests.push(...result);
55
+ }
56
+ }
57
+ return mergeManifests(manifests);
58
+ },
59
+ async configResolved(config) {
60
+ resolvedConfig = config;
61
+ for (const plugin of plugins) {
62
+ if (typeof plugin.configResolved === 'function') {
63
+ await plugin.configResolved.call(this, config);
64
+ }
65
+ else if (plugin.configResolved) {
66
+ throw new TypeError(`object hooks not supported, specify function callback (${plugin.name}.configResolved)`);
67
+ }
68
+ }
69
+ },
70
+ async options(options) {
71
+ if (resolvedConfig.mode === 'production') {
72
+ options.preserveEntrySignatures = 'strict';
73
+ }
74
+ for (const plugin of plugins) {
75
+ if (typeof plugin.options === 'function') {
76
+ options = (await plugin.options.call(this, options)) || options;
77
+ }
78
+ else if (plugin.options) {
79
+ throw new TypeError(`${plugin.name}.options: object hooks not supported, specify function callback`);
80
+ }
81
+ }
82
+ return options;
83
+ },
84
+ async buildStart(options) {
85
+ for (const plugin of plugins) {
86
+ if (typeof plugin.buildStart === 'function') {
87
+ await plugin.buildStart.call(this, options);
88
+ }
89
+ else if (plugin.buildStart) {
90
+ throw new TypeError(`${plugin.name}.buildStart: object hooks not supported, specify function callback`);
91
+ }
92
+ }
93
+ },
94
+ async configureServer(server) {
95
+ for (const plugin of plugins) {
96
+ if (typeof plugin.configureServer === 'function') {
97
+ await plugin.configureServer.call(this, server);
98
+ }
99
+ else if (plugin.configureServer) {
100
+ throw new TypeError(`${plugin.name}.configureServer: object hooks not supported, specify function callback`);
101
+ }
102
+ }
103
+ },
104
+ async resolveId(source, importer, options) {
105
+ for (const plugin of plugins) {
106
+ if (typeof plugin.resolveId === 'function') {
107
+ const result = await plugin.resolveId.call(this, source, importer, options);
108
+ if (result !== undefined)
109
+ return result;
110
+ }
111
+ else if (plugin.resolveId) {
112
+ throw new TypeError(`${plugin.name}.resolveId: object hooks not supported, specify function callback`);
113
+ }
114
+ }
115
+ return undefined;
116
+ },
117
+ async load(id) {
118
+ for (const plugin of plugins) {
119
+ if (typeof plugin.load === 'function') {
120
+ const result = await plugin.load.call(this, id);
121
+ if (result !== undefined)
122
+ return result;
123
+ }
124
+ else if (plugin.load) {
125
+ throw new TypeError(`${plugin.name}.load: object hooks not supported, specify function callback`);
126
+ }
127
+ }
128
+ return undefined;
129
+ },
130
+ async transform(code, id) {
131
+ let result = {};
132
+ for (const plugin of plugins) {
133
+ if (typeof plugin.transform === 'function') {
134
+ // TODO check what happens if there is already meta from other plugins
135
+ const that = await plugin.transform.call(this, code, id);
136
+ if (that && typeof that === 'object') {
137
+ result = deepMergeObject(result, that);
138
+ }
139
+ }
140
+ else if (plugin.transform) {
141
+ throw new TypeError(`${plugin.name}.transform: object hooks not supported, specify function callback`);
142
+ }
143
+ }
144
+ return Object.keys(result).length ? result : undefined;
145
+ },
146
+ async generateBundle(options, bundle, isWrite) {
147
+ for (const plugin of plugins) {
148
+ if (typeof plugin.generateBundle === 'function') {
149
+ await plugin.generateBundle.call(this, options, bundle, isWrite);
150
+ }
151
+ else if (plugin.generateBundle) {
152
+ throw new TypeError(`${plugin.name}.generateBundle: object hooks not supported, specify function callback`);
153
+ }
154
+ }
155
+ },
156
+ async transformIndexHtml(src, ctx) {
157
+ for (const plugin of plugins) {
158
+ if (typeof plugin.transformIndexHtml === 'function') {
159
+ const result = await plugin.transformIndexHtml.call(this, src, ctx);
160
+ if (typeof result === 'string') {
161
+ src = result;
162
+ }
163
+ else if (result) {
164
+ throw new TypeError(`${plugin.name}.transformIndexHtml: tag descriptors not supported, return simple string`);
165
+ }
166
+ }
167
+ else if (plugin.transformIndexHtml) {
168
+ throw new TypeError(`${plugin.name}.transformIndexHtml: object hooks not supported, specify function callback`);
169
+ }
170
+ }
171
+ return src;
172
+ }
173
+ };
174
+ return pluginManifests;
175
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./plugin").VitePluginOxManifestsPluginFn;
2
+ export default _default;
@@ -0,0 +1,63 @@
1
+ import { dirname, posix } from 'node:path';
2
+ import { readdir } from 'node:fs/promises';
3
+ import { normalizePath } from 'vite';
4
+ import { PROJECT_NAME as GETTEXT_PROJECT_NAME, parsePoFile, namespacesFrom } from '@open-xchange/rollup-plugin-po2json';
5
+ import { definePlugin } from './plugin';
6
+ import { applyInputToOptions } from '../util';
7
+ import { PROJECT_NAME } from '../index';
8
+ export default definePlugin(() => {
9
+ const manifests = [];
10
+ let resolvedConfig;
11
+ return {
12
+ name: `${PROJECT_NAME}/gettext-plugin`,
13
+ configResolved(config) {
14
+ resolvedConfig = config;
15
+ },
16
+ async options(options) {
17
+ const gettextPlugin = resolvedConfig.plugins.find(plugin => plugin.name === GETTEXT_PROJECT_NAME);
18
+ if (!gettextPlugin)
19
+ return;
20
+ const { meta: { poFiles, defaultDictionary, defaultLanguage } } = gettextPlugin;
21
+ const input = {};
22
+ // add dictionaries as entry points
23
+ const poDir = dirname(poFiles);
24
+ const files = (await readdir(poDir)).filter(f => f.indexOf(defaultLanguage) >= 0).map(f => normalizePath(`${poDir}/${f}`));
25
+ await Promise.all(files.map(async (file) => {
26
+ const po = await parsePoFile(file);
27
+ for (const namespace of namespacesFrom(po.items)) {
28
+ if (namespace !== defaultDictionary) {
29
+ input[namespace] = `gettext?dictionary=${namespace}`;
30
+ manifests.push({ namespace: 'i18n', path: namespace });
31
+ }
32
+ }
33
+ }));
34
+ input[defaultDictionary] = 'gettext';
35
+ manifests.push({ namespace: 'i18n', path: defaultDictionary });
36
+ if (resolvedConfig.mode === 'production') {
37
+ applyInputToOptions(input, options);
38
+ }
39
+ return options;
40
+ },
41
+ getManifests() {
42
+ if (resolvedConfig.mode === 'production')
43
+ return manifests;
44
+ return manifests.map(manifest => ({ ...manifest, raw: posix.join(resolvedConfig.base, `/@id/${manifest.path}.js`) }));
45
+ },
46
+ generateBundle(_options, bundle) {
47
+ for (const file in bundle) {
48
+ const chunk = bundle[file];
49
+ if (chunk.type !== 'chunk' || !chunk.facadeModuleId)
50
+ continue;
51
+ const modules = Object.keys(chunk.modules);
52
+ if (modules.length === 0)
53
+ modules.push(chunk.facadeModuleId);
54
+ for (const id of modules) {
55
+ const meta = this.getModuleInfo(id)?.meta;
56
+ if (meta.gettext?.dictionary === true) {
57
+ (meta.manifests ??= []).push({ namespace: 'i18n', path: '' });
58
+ }
59
+ }
60
+ }
61
+ }
62
+ };
63
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./plugin").VitePluginOxManifestsPluginFn;
2
+ export default _default;
@@ -0,0 +1,132 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs';
3
+ import fastGlob from 'fast-glob';
4
+ import { definePlugin } from './plugin';
5
+ import { applyInputToOptions, basepath, joinUrlPaths, stringifyJSON } from '../util';
6
+ import { PROJECT_NAME } from '../index';
7
+ async function getManifestEntryFile(basePath, extensions) {
8
+ if (path.extname(basePath)) {
9
+ try {
10
+ await fs.promises.stat(basePath);
11
+ return path.parse(basePath);
12
+ }
13
+ catch (e) {
14
+ throw new Error(`Cannot find file "${basePath}"`);
15
+ }
16
+ }
17
+ for (const ext of extensions) {
18
+ try {
19
+ await fs.promises.stat(`${basePath}.${ext}`);
20
+ return path.parse(`${basePath}.${ext}`);
21
+ }
22
+ catch { }
23
+ }
24
+ throw new Error(`Cannot find file "${basePath}"`);
25
+ }
26
+ export default definePlugin(({ supportedEntryExtensions, entryPoints, manifestsAsEntryPoints }) => {
27
+ const manifestModules = new Map();
28
+ let resolvedConfig;
29
+ let inputOptions;
30
+ let viteManifestPlugin;
31
+ async function buildViteManifests(options, bundle) {
32
+ return new Promise((resolve, reject) => {
33
+ // local async context to satisfy type checker expecting void callback for promise constructor
34
+ (async function () {
35
+ if (typeof viteManifestPlugin.buildStart !== 'function' || typeof viteManifestPlugin.generateBundle !== 'function') {
36
+ throw new Error(`${PROJECT_NAME}: missing required callbacks in plugin 'vite:manifest'`);
37
+ }
38
+ // fake `PluginContext` to be passed to Vite's manifest plugin, needed to extract the asset data
39
+ const context = {
40
+ emitFile(file) {
41
+ if (file.type === 'asset' && typeof file.source === 'string') {
42
+ resolve(JSON.parse(file.source));
43
+ }
44
+ else {
45
+ reject(new Error(`${PROJECT_NAME}: received unexpected manifest data from plugin 'vite:manifest'`));
46
+ }
47
+ },
48
+ getFileName: () => 'Not implemented'
49
+ };
50
+ // manually invoke plugin hooks (in a local async context to satisfy type checker expecting sync promise callbacks)
51
+ await viteManifestPlugin.buildStart.call(context, inputOptions);
52
+ await viteManifestPlugin.generateBundle.call(context, options, bundle, false);
53
+ })().catch(reject);
54
+ });
55
+ }
56
+ return {
57
+ name: `${PROJECT_NAME}/manifests-plugin`,
58
+ config(config) {
59
+ (config.build ??= {}).manifest = true;
60
+ },
61
+ configResolved(config) {
62
+ resolvedConfig = config;
63
+ if (resolvedConfig.mode !== 'production')
64
+ return;
65
+ // extract the vite:manifest plugin from the list
66
+ const index = config.plugins.findIndex(plugin => plugin.name === 'vite:manifest');
67
+ viteManifestPlugin = config.plugins.splice(index, 1)[0];
68
+ },
69
+ async options(options) {
70
+ const input = {};
71
+ if (entryPoints) {
72
+ const entryPointFiles = await fastGlob(entryPoints, { absolute: true });
73
+ for (const entry of entryPointFiles) {
74
+ const baseLength = resolvedConfig.root.length + 1;
75
+ const extLength = path.extname(entry).length;
76
+ input[entry.substring(baseLength, entry.length - extLength)] = entry;
77
+ }
78
+ }
79
+ // 1. load all json files
80
+ const root = resolvedConfig.root;
81
+ const entries = await fastGlob(`${root.replace(/\\/g, '/')}/**/manifest.json`);
82
+ // 2. find every file that is referenced by that json file
83
+ for (const entry of entries) {
84
+ const rawData = await fs.promises.readFile(entry, 'utf-8');
85
+ const json = JSON.parse(rawData);
86
+ const manifests = Array.isArray(json) ? json : [json];
87
+ const manifestDir = path.dirname(entry).substring(root.length + 1);
88
+ await Promise.all(manifests.map(async ({ path: srcManifestEntryPath = joinUrlPaths(manifestDir, 'register'), ...rest }) => {
89
+ const { dir, base } = await getManifestEntryFile(joinUrlPaths(root, srcManifestEntryPath), supportedEntryExtensions);
90
+ const manifestEntryPath = joinUrlPaths(dir, base);
91
+ if (manifestsAsEntryPoints) {
92
+ input[basepath(joinUrlPaths(path.dirname(srcManifestEntryPath), base))] = manifestEntryPath;
93
+ }
94
+ // 3. put the file content except path into the manifest modules
95
+ const modules = manifestModules.get(manifestEntryPath);
96
+ manifestModules.set(manifestEntryPath, (modules || []).concat({ path: '', ...rest }));
97
+ }));
98
+ }
99
+ if (resolvedConfig.mode === 'production') {
100
+ applyInputToOptions(input, options);
101
+ }
102
+ return options;
103
+ },
104
+ buildStart(options) {
105
+ inputOptions = options;
106
+ },
107
+ // specific call to collect all manifests
108
+ getManifests() {
109
+ return Array.from(manifestModules, ([path, manifests]) => manifests.map(m => ({ ...m, path: basepath(path.slice(resolvedConfig.root.length + 1)) }))).flat(1);
110
+ },
111
+ transform(_code, id) {
112
+ if (resolvedConfig.mode !== 'production')
113
+ return;
114
+ const manifests = manifestModules.get(id);
115
+ return manifests ? { meta: { manifests } } : undefined;
116
+ },
117
+ async generateBundle(options, bundle) {
118
+ const viteManifests = await buildViteManifests(options, bundle);
119
+ for (const entry in viteManifests) {
120
+ const chunk = bundle[viteManifests[entry].file];
121
+ if (chunk.type === 'chunk' && chunk.facadeModuleId) {
122
+ viteManifests[entry].meta = this.getModuleInfo(chunk.facadeModuleId)?.meta;
123
+ }
124
+ }
125
+ this.emitFile({
126
+ fileName: 'manifest.json',
127
+ type: 'asset',
128
+ source: stringifyJSON(resolvedConfig, viteManifests)
129
+ });
130
+ }
131
+ };
132
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./plugin").VitePluginOxManifestsPluginFn;
2
+ export default _default;
@@ -0,0 +1,21 @@
1
+ import { definePlugin } from './plugin';
2
+ import { stringifyJSON } from '../util';
3
+ import { PROJECT_NAME } from '../index';
4
+ export default definePlugin(({ meta }) => {
5
+ let resolvedConfig;
6
+ return {
7
+ name: `${PROJECT_NAME}/meta-plugin`,
8
+ configResolved(config) {
9
+ resolvedConfig = config;
10
+ },
11
+ generateBundle() {
12
+ if (meta && Object.keys(meta).length) {
13
+ this.emitFile({
14
+ fileName: 'meta.json',
15
+ type: 'asset',
16
+ source: stringifyJSON(resolvedConfig, meta)
17
+ });
18
+ }
19
+ }
20
+ };
21
+ });
@@ -0,0 +1,24 @@
1
+ import type { Plugin } from 'vite';
2
+ import type { GettextPluginModuleMeta } from '@open-xchange/rollup-plugin-po2json';
3
+ import type { OxManifest, VitePluginOxManifests, VitePluginOxManifestsOptions } from '../index';
4
+ /**
5
+ * Type shape of an internal manifests implementation plugin.
6
+ */
7
+ export interface VitePluginOxManifestsPlugin extends Plugin {
8
+ pluginResolved?(plugin: VitePluginOxManifests): void;
9
+ getManifests?(): OxManifest[] | Promise<OxManifest[]>;
10
+ }
11
+ /**
12
+ * Type shape of internal module metadata used by the manifests plugin.
13
+ */
14
+ export interface VitePluginOxManifestsModuleMeta extends GettextPluginModuleMeta {
15
+ manifests?: OxManifest[];
16
+ }
17
+ /**
18
+ * Plugin generator function.
19
+ */
20
+ export type VitePluginOxManifestsPluginFn = (options: Required<VitePluginOxManifestsOptions>) => VitePluginOxManifestsPlugin;
21
+ /**
22
+ * Helper for type safety. Inspired by Vite's `defineConfig`.
23
+ */
24
+ export declare function definePlugin(fn: VitePluginOxManifestsPluginFn): VitePluginOxManifestsPluginFn;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Helper for type safety. Inspired by Vite's `defineConfig`.
3
+ */
4
+ export function definePlugin(fn) {
5
+ return fn;
6
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./plugin").VitePluginOxManifestsPluginFn;
2
+ export default _default;
@@ -0,0 +1,9 @@
1
+ import { definePlugin } from './plugin';
2
+ import { PROJECT_NAME } from '../index';
3
+ export default definePlugin(options => {
4
+ if ('transformAbsolutePaths' in options)
5
+ console.warn("transformAbsolutePaths is no longer used. Use `base: './'` with vite 3");
6
+ return {
7
+ name: `${PROJECT_NAME}/relative-paths-plugin`
8
+ };
9
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./plugin").VitePluginOxManifestsPluginFn;
2
+ export default _default;
@@ -0,0 +1,66 @@
1
+ import path, { posix } from 'node:path';
2
+ import parseurl from 'parseurl';
3
+ import chokidar from 'chokidar';
4
+ import { definePlugin } from './plugin';
5
+ import { PROJECT_NAME } from '../index';
6
+ function sendJSON(res, data) {
7
+ res.statusCode = 200;
8
+ res.setHeader('Content-Type', 'application/json');
9
+ res.write(JSON.stringify(data));
10
+ return res.end();
11
+ }
12
+ export default definePlugin(({ watch }) => {
13
+ let resolvedConfig;
14
+ let resolvedPlugin;
15
+ let manifestRegex;
16
+ let depsRegex;
17
+ return {
18
+ name: `${PROJECT_NAME}/serve-plugin`,
19
+ pluginResolved(plugin) {
20
+ resolvedPlugin = plugin;
21
+ },
22
+ configResolved(config) {
23
+ resolvedConfig = config;
24
+ manifestRegex = new RegExp(`^${config.base}(api/manifest.json|manifests)$`);
25
+ depsRegex = new RegExp(`^${config.base}(api/deps.json|dependencies)$`);
26
+ },
27
+ configureServer({ ws, middlewares, moduleGraph }) {
28
+ function addTimestamp(manifests) {
29
+ for (const manifest of manifests) {
30
+ // TODO what about other file types?
31
+ const id = `${resolvedConfig.root}/${manifest.path}.js`;
32
+ const moduleNode = moduleGraph.idToModuleMap.get(id);
33
+ const hmrTS = moduleNode?.lastHMRTimestamp;
34
+ if (hmrTS)
35
+ manifest.raw = posix.join(resolvedConfig.base, `/${manifest.path}.js?t=${hmrTS}`);
36
+ }
37
+ }
38
+ middlewares.use((req, res, next) => {
39
+ if (req.method !== 'GET')
40
+ return next();
41
+ const url = parseurl(req);
42
+ if (!url?.path)
43
+ return next();
44
+ if (manifestRegex.test(url.path)) {
45
+ resolvedPlugin.getManifests().then(manifests => {
46
+ addTimestamp(manifests);
47
+ sendJSON(res, manifests);
48
+ }, next);
49
+ return;
50
+ }
51
+ if (depsRegex.test(url.path)) {
52
+ return sendJSON(res, {});
53
+ }
54
+ next();
55
+ });
56
+ if (watch) {
57
+ const watcher = chokidar.watch(path.join(resolvedConfig.root, '**/manifest.json'))
58
+ .on('ready', () => {
59
+ watcher.on('all', path => {
60
+ ws.send({ type: 'full-reload', path });
61
+ });
62
+ });
63
+ }
64
+ }
65
+ };
66
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("./plugin").VitePluginOxManifestsPluginFn;
2
+ export default _default;