Skip to content

Commit e2d4e57

Browse files
committed
Add inline Vite plugin for Nimiq integration
1 parent a37c5d6 commit e2d4e57

File tree

7 files changed

+217
-326
lines changed

7 files changed

+217
-326
lines changed

pnpm-lock.yaml

Lines changed: 75 additions & 248 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

starters/hub-api-ts/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vercel

starters/hub-api-ts/src/tests/hub-api.browser.test.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ it('opens Hub popup and verifies it loads the Hub interface', async () => {
3232

3333
// Override window.open to capture the popup reference
3434
const originalOpen = window.open
35-
window.open = function (...args: Parameters<typeof window.open>) {
35+
window.open = function (...args: Parameters<typeof window.open>): Window | null {
3636
const url = args[0]?.toString() || ''
3737

3838
// Check if it's the Hub
@@ -41,12 +41,12 @@ it('opens Hub popup and verifies it loads the Hub interface', async () => {
4141
hubPopupUrl = url
4242

4343
// Actually open the popup so we can inspect it
44-
hubPopup = originalOpen.apply(window, args)
44+
hubPopup = originalOpen.apply(window, args) as Window | null
4545
return hubPopup
4646
}
4747

48-
return originalOpen.apply(window, args)
49-
} as typeof window.open
48+
return originalOpen.apply(window, args) as Window | null
49+
}
5050

5151
// Import and initialize the app
5252
await import('../main')
@@ -65,29 +65,32 @@ it('opens Hub popup and verifies it loads the Hub interface', async () => {
6565
expect(hubPopup).toBeTruthy()
6666

6767
// Try to verify the popup loaded (if accessible due to CORS/same-origin policy)
68-
if (hubPopup && !hubPopup.closed) {
69-
try {
70-
// Wait a bit for the Hub to load
71-
await sleep(3000)
72-
73-
// Check if we can access the popup's location
74-
const popupLocation = hubPopup.location.href
75-
expect(popupLocation).toContain('hub.nimiq')
76-
console.log('✅ Hub popup verified - URL:', popupLocation)
77-
78-
// Close the popup
79-
hubPopup.close()
80-
}
81-
catch (error) {
82-
// If we get a cross-origin error, that's actually good - it means the real Hub loaded
83-
const errorMessage = error instanceof Error ? error.message : String(error)
84-
if (errorMessage.includes('cross-origin') || errorMessage.includes('SecurityError')) {
85-
console.log('✅ Hub popup loaded (cross-origin - real Hub domain)')
86-
console.log(' Expected cross-origin restriction confirms real Hub loaded')
87-
hubPopup.close()
68+
if (hubPopup) {
69+
const popup = hubPopup as Window
70+
if (!popup.closed) {
71+
try {
72+
// Wait a bit for the Hub to load
73+
await sleep(3000)
74+
75+
// Check if we can access the popup's location
76+
const popupLocation = popup.location.href
77+
expect(popupLocation).toContain('hub.nimiq')
78+
console.log('✅ Hub popup verified - URL:', popupLocation)
79+
80+
// Close the popup
81+
popup.close()
8882
}
89-
else {
90-
throw error
83+
catch (error) {
84+
// If we get a cross-origin error, that's actually good - it means the real Hub loaded
85+
const errorMessage = error instanceof Error ? error.message : String(error)
86+
if (errorMessage.includes('cross-origin') || errorMessage.includes('SecurityError')) {
87+
console.log('✅ Hub popup loaded (cross-origin - real Hub domain)')
88+
console.log(' Expected cross-origin restriction confirms real Hub loaded')
89+
popup.close()
90+
}
91+
else {
92+
throw error
93+
}
9194
}
9295
}
9396
}

starters/react-ts/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
"playwright": "^1.55.1",
3333
"typescript": "^5.9.2",
3434
"vite": "^7.1.7",
35-
"vite-plugin-top-level-await": "^1.6.0",
3635
"vite-plugin-wasm": "^3.5.0",
3736
"vitest": "^3.2.4"
3837
}

starters/react-ts/vite.config.ts

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import type { Plugin } from 'vite'
12
import { copyFile, cp, mkdir } from 'node:fs/promises'
23
import path from 'node:path'
3-
import { fileURLToPath, URL } from 'node:url'
44

5+
import { fileURLToPath, URL } from 'node:url'
56
import react from '@vitejs/plugin-react'
67
import { defineConfig } from 'vite'
7-
import topLevelAwait from 'vite-plugin-top-level-await'
88
import wasm from 'vite-plugin-wasm'
99

10-
function copyComlinkPlugin() {
10+
function copyComlinkPlugin(): Plugin {
1111
return {
1212
name: 'copy-comlink-worker-dependency',
1313
apply: 'build',
@@ -21,57 +21,79 @@ function copyComlinkPlugin() {
2121
await mkdir(distAssetsDir, { recursive: true })
2222
await copyFile(src, dest)
2323

24+
// Copy worker WASM files if they exist
2425
const workerSrcDir = path.join(distDir, 'worker-wasm')
2526
const workerDestDir = path.join(distAssetsDir, 'worker-wasm')
26-
await cp(workerSrcDir, workerDestDir, { recursive: true })
27+
try {
28+
await cp(workerSrcDir, workerDestDir, { recursive: true })
29+
}
30+
catch (error) {
31+
// Ignore if worker-wasm doesn't exist
32+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
33+
throw error
34+
}
35+
}
2736
},
2837
}
2938
}
3039

40+
/**
41+
* Vite plugin for Nimiq blockchain integration
42+
* Configures WebAssembly support and optimizations required for @nimiq/core
43+
*
44+
* Note: This plugin does not include top-level await support. Modern browsers
45+
* support top-level await natively. If you need support for older browsers,
46+
* you can add vite-plugin-top-level-await to your plugins array manually.
47+
*
48+
* @param {object} [options] - Plugin options
49+
* @param {boolean} [options.worker] - Configure worker support for WASM
50+
* @returns {import('vite').Plugin[]} Array of Vite plugins
51+
*/
52+
function nimiq(options = { worker: true }) {
53+
return [
54+
wasm(),
55+
{
56+
name: 'vite-plugin-nimiq',
57+
config() {
58+
return {
59+
optimizeDeps: {
60+
exclude: ['@nimiq/core'],
61+
},
62+
build: {
63+
target: 'esnext',
64+
rollupOptions: {
65+
output: {
66+
format: 'es',
67+
},
68+
},
69+
},
70+
...(options.worker && {
71+
worker: {
72+
format: 'es',
73+
plugins: () => [wasm()],
74+
},
75+
}),
76+
}
77+
},
78+
},
79+
]
80+
}
81+
3182
// https://vite.dev/config/
3283
export default defineConfig({
3384
plugins: [
3485
react(),
35-
wasm(),
36-
topLevelAwait({
37-
// The module that contains the top-level await
38-
promiseExportName: '__tla',
39-
// The function to generate the promise export name
40-
promiseImportName: i => `__tla_${i}`,
41-
}),
86+
nimiq(),
4287
copyComlinkPlugin(),
4388
],
44-
worker: {
45-
format: 'es',
46-
rollupOptions: {
47-
output: {
48-
entryFileNames: 'assets/[name]-[hash].js',
49-
chunkFileNames: 'assets/[name]-[hash].js',
50-
assetFileNames: 'assets/[name]-[hash].[ext]',
51-
},
52-
},
53-
plugins: () => [
54-
wasm(),
55-
topLevelAwait({
56-
promiseExportName: '__tla',
57-
promiseImportName: i => `__tla_${i}`,
58-
}),
59-
],
60-
},
6189
resolve: {
6290
alias: {
6391
'@': fileURLToPath(new URL('./src', import.meta.url)),
6492
},
6593
},
66-
optimizeDeps: {
67-
exclude: ['@nimiq/core'],
68-
},
69-
// Additional build configuration for Nimiq
7094
build: {
71-
target: 'esnext',
7295
rollupOptions: {
7396
output: {
74-
format: 'es',
7597
entryFileNames: 'assets/[name]-[hash].js',
7698
chunkFileNames: 'assets/[name]-[hash].js',
7799
assetFileNames: 'assets/[name]-[hash].[ext]',

starters/vue-ts/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
"playwright": "^1.55.1",
3232
"typescript": "^5.9.2",
3333
"vite": "^7.1.7",
34-
"vite-plugin-top-level-await": "^1.6.0",
3534
"vite-plugin-vue-devtools": "^8.0.0",
3635
"vite-plugin-wasm": "^3.5.0",
3736
"vitest": "^3.2.4",

starters/vue-ts/vite.config.ts

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
import type { Plugin } from 'vite'
12
import { copyFile, cp, mkdir } from 'node:fs/promises'
23
import path from 'node:path'
3-
import { fileURLToPath, URL } from 'node:url'
44

5+
import { fileURLToPath, URL } from 'node:url'
56
import vue from '@vitejs/plugin-vue'
67
import { defineConfig } from 'vite'
7-
import topLevelAwait from 'vite-plugin-top-level-await'
88
import vueDevTools from 'vite-plugin-vue-devtools'
99
import wasm from 'vite-plugin-wasm'
1010

11-
function copyComlinkPlugin() {
11+
function copyComlinkPlugin(): Plugin {
1212
return {
1313
name: 'copy-comlink-worker-dependency',
1414
apply: 'build',
@@ -22,35 +22,75 @@ function copyComlinkPlugin() {
2222
await mkdir(distAssetsDir, { recursive: true })
2323
await copyFile(src, dest)
2424

25+
// Copy worker WASM files if they exist
2526
const workerSrcDir = path.join(distDir, 'worker-wasm')
2627
const workerDestDir = path.join(distAssetsDir, 'worker-wasm')
27-
await cp(workerSrcDir, workerDestDir, { recursive: true })
28+
try {
29+
await cp(workerSrcDir, workerDestDir, { recursive: true })
30+
}
31+
catch (error) {
32+
// Ignore if worker-wasm doesn't exist
33+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
34+
throw error
35+
}
36+
}
2837
},
2938
}
3039
}
3140

41+
/**
42+
* Vite plugin for Nimiq blockchain integration
43+
* Configures WebAssembly support and optimizations required for @nimiq/core
44+
*
45+
* Note: This plugin does not include top-level await support. Modern browsers
46+
* support top-level await natively. If you need support for older browsers,
47+
* you can add vite-plugin-top-level-await to your plugins array manually.
48+
*
49+
* @param {object} [options] - Plugin options
50+
* @param {boolean} [options.worker] - Configure worker support for WASM
51+
* @returns {import('vite').Plugin[]} Array of Vite plugins
52+
*/
53+
function nimiq(options = { worker: true }) {
54+
return [
55+
wasm(),
56+
{
57+
name: 'vite-plugin-nimiq',
58+
config() {
59+
return {
60+
optimizeDeps: {
61+
exclude: ['@nimiq/core'],
62+
},
63+
build: {
64+
target: 'esnext',
65+
rollupOptions: {
66+
output: {
67+
format: 'es',
68+
},
69+
},
70+
},
71+
...(options.worker && {
72+
worker: {
73+
format: 'es',
74+
plugins: () => [wasm()],
75+
},
76+
}),
77+
}
78+
},
79+
},
80+
]
81+
}
82+
3283
// https://vite.dev/config/
3384
export default defineConfig({
3485
plugins: [
3586
vue(),
3687
vueDevTools(),
37-
wasm(),
38-
topLevelAwait(),
88+
nimiq(),
3989
copyComlinkPlugin(),
4090
],
41-
worker: {
42-
format: 'es',
43-
plugins: () => [
44-
wasm(),
45-
topLevelAwait(),
46-
],
47-
},
4891
resolve: {
4992
alias: {
5093
'@': fileURLToPath(new URL('./src', import.meta.url)),
5194
},
5295
},
53-
optimizeDeps: {
54-
exclude: ['@nimiq/core'],
55-
},
5696
})

0 commit comments

Comments
 (0)