@open-xchange/vite-plugin-ox-manifests 0.4.2 → 0.4.4-pre2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-xchange/vite-plugin-ox-manifests",
3
- "version": "0.4.2",
3
+ "version": "0.4.4-pre2",
4
4
  "description": "A vite plugin to concat and serve ox manifests",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,5 +1,5 @@
1
1
  import { applyInputToOptions } from '../util.js'
2
- import path from 'path'
2
+ import path, { posix } from 'path'
3
3
  import { readdir } from 'fs/promises'
4
4
  import { normalizePath } from 'vite'
5
5
  import { parsePoFile, namespacesFrom } from '@open-xchange/rollup-plugin-po2json/lib/po2json.js'
@@ -44,7 +44,7 @@ export default function () {
44
44
 
45
45
  getManifests () {
46
46
  if (resolvedConfig.mode !== 'production') {
47
- return manifests.map(({ namespace, path }) => ({ namespace, raw: `/@id/${path}.js`, path }))
47
+ return manifests.map(({ namespace, path }) => ({ namespace, raw: posix.join(resolvedConfig.base, `/@id/${path}.js`), path }))
48
48
  }
49
49
  return manifests
50
50
  },
@@ -54,9 +54,11 @@ export default function () {
54
54
  const chunk = bundle[file]
55
55
  if (!chunk.facadeModuleId) continue
56
56
 
57
- Object.keys(chunk.modules).forEach(id => {
57
+ const modules = Object.keys(chunk.modules)
58
+ if (modules.length === 0) modules.push(chunk.facadeModuleId)
59
+ modules.forEach(id => {
58
60
  const meta = this.getModuleInfo(id)?.meta
59
- if (!meta?.gettext?.dictionary === true) return
61
+ if (meta?.gettext?.dictionary !== true) return
60
62
 
61
63
  meta.manifests = meta.manifests || []
62
64
  meta.manifests.push({ namespace: 'i18n' })
@@ -1,4 +1,4 @@
1
- import path from 'path'
1
+ import path, { posix } from 'path'
2
2
  import parseurl from 'parseurl'
3
3
  import chokidar from 'chokidar'
4
4
 
@@ -30,7 +30,7 @@ export default function ({ watch } = {}) {
30
30
  if (!moduleNode) return
31
31
  const hmrTS = moduleNode.lastHMRTimestamp
32
32
  if (!hmrTS) return
33
- manifest.raw = `/${manifest.path}.js?t=${hmrTS}`
33
+ manifest.raw = posix.join(resolvedConfig.base, `/${manifest.path}.js?t=${hmrTS}`)
34
34
  })
35
35
  }
36
36
 
@@ -1,6 +1,6 @@
1
1
  import fastGlob from 'fast-glob'
2
2
  import fs from 'fs'
3
- import path from 'path'
3
+ import path, { posix } from 'path'
4
4
  import { applyInputToOptions, basepath } from '../util.js'
5
5
 
6
6
  function getRequirements (entry) {
@@ -17,7 +17,7 @@ function getRequirements (entry) {
17
17
  const moduleInfo = this.getModuleInfo(first)
18
18
  if (moduleInfo.isEntry) {
19
19
  if (moduleInfo.meta?.manifests) {
20
- entryPoints.push.apply(entryPoints, moduleInfo.meta.manifests)
20
+ entryPoints.push.apply(entryPoints, moduleInfo.meta.manifests.map(manifest => ({ requires: 'true', ...manifest })))
21
21
  continue
22
22
  }
23
23
  }
@@ -33,6 +33,7 @@ function getRequirements (entry) {
33
33
  function mergeRequirements (requirements) {
34
34
  if (requirements.length === 0) return
35
35
  if (requirements.length === 1) return requirements[0]
36
+ if (requirements.includes('true')) return
36
37
  return requirements.map(c => {
37
38
  // check if is just a simple string
38
39
  if (/^[-\w]*$/.test(c)) return c
@@ -107,7 +108,7 @@ export default function ({ autoloadSettings } = {}) {
107
108
  const manifest = { ...m, path: newPath }
108
109
  const moduleNode = moduleGraph?.idToModuleMap.get(path)
109
110
  if (moduleNode?.lastHMRTimestamp) {
110
- manifest.raw = `/${manifest.path}.js?t=${moduleNode.lastHMRTimestamp}`
111
+ manifest.raw = posix.join(resolvedConfig.base, `/${manifest.path}.js?t=${moduleNode.lastHMRTimestamp}`)
111
112
  }
112
113
  return manifest
113
114
  }
package/src/util.js CHANGED
@@ -38,3 +38,20 @@ export function deepMergeObject (a, b) {
38
38
 
39
39
  return result
40
40
  }
41
+
42
+ export function waitForReload (server) {
43
+ return new Promise(resolve => {
44
+ const prev = server.ws.send
45
+ server.ws.send = function ({ type } = {}) {
46
+ try {
47
+ return prev.apply(this, arguments)
48
+ } finally {
49
+ if (type === 'full-reload') resolve()
50
+ }
51
+ }
52
+ })
53
+ }
54
+
55
+ export function wait (millis) {
56
+ return new Promise(resolve => setTimeout(resolve, millis))
57
+ }
@@ -0,0 +1,4 @@
1
+ import gt from 'gettext'
2
+
3
+ export const five = 5
4
+ export default gt('five')
@@ -0,0 +1,16 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "PO-Revision-Date: 2014-01-15 14:13+0100\n"
5
+ "Last-Translator: Julian Bäume <julian.baeume@open-xchange.com>\n"
6
+ "Language-Team: German <julian.baeume@open-xchange.com>\n"
7
+ "Language: de_DE\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
12
+ "X-Generator: Lokalize 1.5\n"
13
+
14
+ #: module:i18n
15
+ msgid "Hello world!"
16
+ msgstr "Hallo Welt!"
@@ -0,0 +1,16 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "PO-Revision-Date: 2014-01-15 14:13+0100\n"
5
+ "Last-Translator: Julian Bäume <julian.baeume@open-xchange.com>\n"
6
+ "Language-Team: German <julian.baeume@open-xchange.com>\n"
7
+ "Language: en_US\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
12
+ "X-Generator: Lokalize 1.5\n"
13
+
14
+ #: module:i18n
15
+ msgid "Hello world!"
16
+ msgstr ""
@@ -0,0 +1,68 @@
1
+ import { describe, it, expect, afterEach } from '@jest/globals'
2
+ import { build, createServer } from 'vite'
3
+ import path from 'path'
4
+ import vitePluginOxManifests from '../../index'
5
+ import rollupPluginPo2Json from '@open-xchange/rollup-plugin-po2json'
6
+ import { getFileFromBundle, getPort } from '../util'
7
+ import axios from 'axios'
8
+
9
+ const PORT = getPort()
10
+ const __dirname = path.dirname(new URL(import.meta.url).pathname)
11
+
12
+ describe('Dictionary in modules with dynamic imports', function () {
13
+ let server
14
+
15
+ afterEach(async function () {
16
+ if (server) {
17
+ await server.close()
18
+ server = null
19
+ }
20
+ })
21
+
22
+ it('works', async function () {
23
+ const bundle = await build({
24
+ root: __dirname,
25
+ logLevel: 'silent',
26
+ build: {
27
+ write: false,
28
+ rollupOptions: {
29
+ input: { }
30
+ }
31
+ },
32
+ plugins: [rollupPluginPo2Json({
33
+ poFiles: __dirname + '/i18n/*.po'
34
+ }), vitePluginOxManifests({
35
+
36
+ })]
37
+ })
38
+
39
+ const manifestFile = getFileFromBundle('manifest', bundle)
40
+ const manifests = JSON.parse(manifestFile.source)
41
+ expect(Object.keys(manifests)).toHaveLength(6)
42
+ expect(manifests['register.js'].meta.manifests[0].namespace).toEqual('test')
43
+ expect(manifests['../../i18n.js'].meta.gettext.dictionary).toEqual(true)
44
+ expect(manifests['../../i18n.js'].meta.manifests[0].namespace).toEqual('i18n')
45
+ })
46
+
47
+ it('works in dev mode', async function () {
48
+ server = await createServer({
49
+ root: __dirname,
50
+ logLevel: 'silent',
51
+ plugins: [rollupPluginPo2Json({
52
+ poFiles: __dirname + '/i18n/*.po'
53
+ }), vitePluginOxManifests({
54
+
55
+ })]
56
+ })
57
+ await server.listen(PORT)
58
+
59
+ const res = await axios({ baseURL: `http://127.0.0.1:${PORT}/api/manifest.json` })
60
+ const manifests = res.data
61
+
62
+ expect(manifests).toHaveLength(2)
63
+ expect(manifests[0].namespace).toEqual('i18n')
64
+ expect(manifests[0].path).toEqual('i18n')
65
+ expect(manifests[1].namespace).toEqual('test')
66
+ expect(manifests[1].path).toContain('register')
67
+ })
68
+ })
@@ -0,0 +1,3 @@
1
+ {
2
+ "namespace": "test"
3
+ }
@@ -0,0 +1,6 @@
1
+ import gt from 'gettext'
2
+
3
+ export async function doSomethingDynamic () {
4
+ const { five } = await import('./another_chunk.js')
5
+ console.log(gt('Hello world!'), five)
6
+ }
@@ -0,0 +1,122 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from '@jest/globals'
2
+ import { createServer } from 'vite'
3
+ import path from 'path'
4
+ import vitePluginOxManifests from '../../index'
5
+ import { getPort } from '../util'
6
+ import axios from 'axios'
7
+ import { readFileSync, writeFileSync } from 'fs'
8
+ import { waitForReload } from '../../src/util'
9
+ import vitePluginOxExternals from '@open-xchange/vite-plugin-ox-externals'
10
+
11
+ const __dirname = path.dirname(new URL(import.meta.url).pathname)
12
+ const files = ['register.js', 'settings.js']
13
+ const PORT = getPort()
14
+
15
+ describe('HMR', function () {
16
+ let server, data
17
+
18
+ beforeEach(function () {
19
+ data = files.map(f => readFileSync(path.join(__dirname, f)))
20
+ })
21
+
22
+ afterEach(async function () {
23
+ data.forEach((d, i) => writeFileSync(path.join(__dirname, files[i]), d))
24
+ data = null
25
+ await server?.close()
26
+ server = null
27
+ })
28
+
29
+ it('adds timestamps to manifest files', async function () {
30
+ server = await createServer({
31
+ root: __dirname,
32
+ logLevel: 'silent',
33
+ plugins: [vitePluginOxManifests({
34
+
35
+ }), vitePluginOxExternals({
36
+ prefix: '$'
37
+ })]
38
+ })
39
+ await server.listen(PORT)
40
+
41
+ // fetch this file to start watcher
42
+ await axios({ baseURL: `http://127.0.0.1:${PORT}/register.js` })
43
+
44
+ const { data: manifests } = await axios({ baseURL: `http://127.0.0.1:${PORT}/manifests` })
45
+ expect(Object.keys(manifests)).toHaveLength(2)
46
+ expect(manifests[1]).not.toContain('raw')
47
+
48
+ writeFileSync(path.join(__dirname, 'register.js'), 'console.log("Changed")')
49
+
50
+ await waitForReload(server)
51
+
52
+ const { data: manifestsWithHMR } = await axios({ baseURL: `http://127.0.0.1:${PORT}/manifests` })
53
+ expect(Object.keys(manifestsWithHMR)).toHaveLength(2)
54
+ expect(manifestsWithHMR[1].namespace).toEqual('test')
55
+ expect(manifestsWithHMR[1].raw).toMatch(/\/register\.js\?t=\d+/)
56
+ })
57
+
58
+ it('adds timestamps to settings manifest files', async function () {
59
+ server = await createServer({
60
+ root: __dirname,
61
+ logLevel: 'silent',
62
+ plugins: [vitePluginOxManifests({
63
+
64
+ }), vitePluginOxExternals({
65
+ prefix: '$'
66
+ })]
67
+ })
68
+ await server.listen(PORT)
69
+
70
+ // fetch this file to start watcher
71
+ await axios({ baseURL: `http://127.0.0.1:${PORT}/settings.js` })
72
+
73
+ const { data: manifests } = await axios({ baseURL: `http://127.0.0.1:${PORT}/manifests` })
74
+ expect(Object.keys(manifests)).toHaveLength(2)
75
+ expect(manifests[0]).not.toContain('raw')
76
+
77
+ writeFileSync(path.join(__dirname, 'settings.js'), `/* a comment */${data[1].toString()}`)
78
+
79
+ await waitForReload(server)
80
+
81
+ const { data: manifestsWithHMR } = await axios({ baseURL: `http://127.0.0.1:${PORT}/manifests` })
82
+ expect(Object.keys(manifestsWithHMR)).toHaveLength(2)
83
+ expect(manifestsWithHMR[0].namespace).toEqual('settings')
84
+ expect(manifestsWithHMR[0].raw).toMatch(/\/settings\.js\?t=\d+/)
85
+ })
86
+
87
+ it('includes base-path in manifests', async function () {
88
+ server = await createServer({
89
+ root: __dirname,
90
+ logLevel: 'silent',
91
+ base: '/appsuite',
92
+ plugins: [vitePluginOxManifests({
93
+
94
+ }), vitePluginOxExternals({
95
+ prefix: '$'
96
+ })]
97
+ })
98
+ await server.listen(PORT)
99
+
100
+ // fetch this file to start watcher
101
+ await axios({ baseURL: `http://127.0.0.1:${PORT}/appsuite/register.js` })
102
+ await axios({ baseURL: `http://127.0.0.1:${PORT}/appsuite/settings.js` })
103
+
104
+ const { data: manifests } = await axios({ baseURL: `http://127.0.0.1:${PORT}/appsuite/manifests` })
105
+ expect(Object.keys(manifests)).toHaveLength(2)
106
+ expect(manifests[0]).not.toContain('raw')
107
+ expect(manifests[1]).not.toContain('raw')
108
+
109
+ writeFileSync(path.join(__dirname, 'register.js'), 'console.log("Changed")')
110
+ await waitForReload(server)
111
+
112
+ writeFileSync(path.join(__dirname, 'settings.js'), `/* a comment */${data[1].toString()}`)
113
+ await waitForReload(server)
114
+
115
+ const { data: manifestsWithHMR } = await axios({ baseURL: `http://127.0.0.1:${PORT}/appsuite/manifests` })
116
+ expect(Object.keys(manifestsWithHMR)).toHaveLength(2)
117
+ expect(manifestsWithHMR[0].namespace).toEqual('settings')
118
+ expect(manifestsWithHMR[0].raw).toMatch(/\/appsuite\/settings\.js\?t=\d+/)
119
+ expect(manifestsWithHMR[1].namespace).toEqual('test')
120
+ expect(manifestsWithHMR[1].raw).toMatch(/\/appsuite\/register\.js\?t=\d+/)
121
+ })
122
+ })
@@ -0,0 +1,3 @@
1
+ {
2
+ "namespace": "test"
3
+ }
@@ -0,0 +1 @@
1
+ console.log('Hello world!')
@@ -0,0 +1,3 @@
1
+ import { Settings } from '$/io.ox/core/settings'
2
+
3
+ export const settings = new Settings('test', () => {})
@@ -1,3 +1,4 @@
1
1
  import { settings } from './settings'
2
+ import { settings as other } from './other-settings'
2
3
 
3
- console.log('Hello world', settings)
4
+ console.log('Hello world', settings, other)
@@ -22,8 +22,30 @@ describe('Settings like in core, with requirements', function () {
22
22
  })
23
23
  const manifestFile = getFileFromBundle('manifest', bundle)
24
24
  const manifests = JSON.parse(manifestFile.source)
25
- expect(Object.keys(manifests)).toHaveLength(2)
25
+ expect(Object.keys(manifests)).toHaveLength(4)
26
26
  expect(manifests['settings.js'].meta.manifests[0].namespace).toEqual('settings')
27
27
  expect(manifests['settings.js'].meta.manifests[0].requires).toEqual('cap')
28
28
  })
29
+
30
+ it('merges requirements for manifests', async () => {
31
+ const bundle = await build({
32
+ root: path.dirname(new URL(import.meta.url).pathname),
33
+ logLevel: 'silent',
34
+ build: {
35
+ write: false,
36
+ rollupOptions: {
37
+ input: {},
38
+ external: ['@/io.ox/core/settings']
39
+ }
40
+ },
41
+ plugins: [vitePluginOxManifests({
42
+
43
+ })]
44
+ })
45
+
46
+ const manifestFile = getFileFromBundle('manifest', bundle)
47
+ const manifests = JSON.parse(manifestFile.source)
48
+ expect(Object.keys(manifests)).toHaveLength(4)
49
+ expect(manifests['other-settings.js'].meta.manifests[0].requires).toBeUndefined()
50
+ })
29
51
  })
@@ -1,5 +1,8 @@
1
- {
1
+ [{
2
2
  "namespace": "test",
3
3
  "path": "index",
4
4
  "requires": "cap"
5
- }
5
+ }, {
6
+ "namespace": "test",
7
+ "path": "other"
8
+ }]
@@ -0,0 +1,3 @@
1
+ import { Settings } from '@/io.ox/core/settings'
2
+
3
+ export const settings = new Settings('other', () => {})
@@ -0,0 +1,3 @@
1
+ import { settings as other } from './other-settings'
2
+
3
+ console.log('Hello world', other)