Skip to content

Commit 6b66be3

Browse files
authored
Merge pull request #182 from Web3NL:feat--extend-canister-dapp-config-plugin
fix: split runtime functions from build time plugin
2 parents 69ca140 + 6c8c4e2 commit 6b66be3

5 files changed

Lines changed: 182 additions & 167 deletions

File tree

my-canister-dapp-js/vite-plugin-canister-dapp/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
".": {
2020
"types": "./dist/index.d.ts",
2121
"import": "./dist/index.js"
22+
},
23+
"./runtime": {
24+
"types": "./dist/runtime.d.ts",
25+
"import": "./dist/runtime.js"
2226
}
2327
},
2428
"files": [

my-canister-dapp-js/vite-plugin-canister-dapp/src/global.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CanisterDappEnvironmentConfig } from './canister-dapp-environment-config';
1+
import type { CanisterDappEnvironmentConfig } from './plugin';
22

33
declare global {
44
/**

my-canister-dapp-js/vite-plugin-canister-dapp/src/index.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,6 @@ function notEmptyString(value: unknown): value is string {
314314
// Export new general-purpose canister dapp environment config plugin
315315
export {
316316
canisterDappEnvironmentConfig,
317-
inferEnvironment,
318-
isDevMode,
319-
inferCanisterId,
320317
type CanisterDappEnvironmentConfig,
321318
type CanisterDappEnvironmentPluginConfig,
322-
} from './canister-dapp-environment-config.js';
319+
} from './plugin';

my-canister-dapp-js/vite-plugin-canister-dapp/src/canister-dapp-environment-config.ts renamed to my-canister-dapp-js/vite-plugin-canister-dapp/src/plugin.ts

Lines changed: 1 addition & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import type { Plugin } from 'vite';
2-
import { Principal } from '@dfinity/principal';
3-
import { inferCanisterIdFromLocation } from '@web3nl/my-canister-dashboard';
42

53
/**
64
* Environment configuration interface for Internet Computer Canister Dapp
@@ -117,7 +115,7 @@ const DEFAULT_PROD_CONFIG: CanisterDappEnvironmentConfig = {
117115
*
118116
* Frontend usage with helper functions:
119117
* ```typescript
120-
* import { inferEnvironment, isDevMode, inferCanisterId } from '@web3nl/vite-plugin-canister-dapp';
118+
* import { inferEnvironment, isDevMode, inferCanisterId } from '@web3nl/vite-plugin-canister-dapp/runtime';
121119
*
122120
* const config = inferEnvironment(); // Synchronous! Returns { host, identityProvider }
123121
* const canisterId = inferCanisterId(); // Synchronous! Returns Principal
@@ -270,165 +268,6 @@ export function canisterDappEnvironmentConfig(
270268
};
271269
}
272270

273-
/**
274-
* Detect if the application is running in development mode based on URL origin
275-
*
276-
* Development mode is detected when the origin:
277-
* - Starts with 'http://' (not https)
278-
* - Contains 'localhost'
279-
* - Contains '127.0.0.1'
280-
*
281-
* This function is used internally by `inferEnvironment()` and `isDevMode()`.
282-
*
283-
* @returns true if running in development mode, false otherwise
284-
*/
285-
function detectDevModeFromOrigin(): boolean {
286-
if (typeof window === 'undefined' || !window.location) {
287-
// SSR or non-browser environment, default to production
288-
return false;
289-
}
290-
291-
const origin = window.location.origin.toLowerCase();
292-
return (
293-
origin.startsWith('http://') ||
294-
origin.includes('localhost') ||
295-
origin.includes('127.0.0.1')
296-
);
297-
}
298-
299-
/**
300-
* Infer the canister dapp environment at runtime based on URL origin
301-
*
302-
* This helper function automatically determines the environment configuration by
303-
* analyzing the current URL origin. It returns the development configuration if
304-
* the origin indicates a development environment (http://, localhost, or 127.0.0.1),
305-
* otherwise it returns the production configuration.
306-
*
307-
* Both configurations are embedded in the build by the Vite plugin, so no network
308-
* requests are needed. This enables building a single WASM that works in all environments.
309-
*
310-
* The result is cached for performance, so subsequent calls will return the cached value.
311-
*
312-
* Example usage:
313-
* ```typescript
314-
* import { inferEnvironment } from '@web3nl/vite-plugin-canister-dapp';
315-
*
316-
* export function getConfig() {
317-
* const config = inferEnvironment();
318-
* console.log('Running in:', config.host);
319-
* return config;
320-
* }
321-
* ```
322-
*
323-
* @returns The environment configuration (dev or prod based on URL origin)
324-
*/
325-
export function inferEnvironment(): CanisterDappEnvironmentConfig {
326-
if (configCache !== null) {
327-
return configCache;
328-
}
329-
330-
// Detect environment based on URL origin
331-
const isDev = detectDevModeFromOrigin();
332-
333-
// Get the appropriate config from the injected global constants
334-
if (isDev) {
335-
configCache =
336-
typeof __CANISTER_DAPP_DEV_CONFIG__ !== 'undefined'
337-
? __CANISTER_DAPP_DEV_CONFIG__
338-
: DEFAULT_DEV_CONFIG;
339-
} else {
340-
configCache =
341-
typeof __CANISTER_DAPP_PROD_CONFIG__ !== 'undefined'
342-
? __CANISTER_DAPP_PROD_CONFIG__
343-
: DEFAULT_PROD_CONFIG;
344-
}
345-
346-
return configCache;
347-
}
348-
349-
/**
350-
* Check if the application is running in development mode based on URL origin
351-
*
352-
* This function checks the URL origin to determine if the application is running
353-
* in development mode. Development mode is detected when the origin:
354-
* - Starts with 'http://' (not https)
355-
* - Contains 'localhost'
356-
* - Contains '127.0.0.1'
357-
*
358-
* The result is cached for performance, so subsequent calls will return the cached value.
359-
*
360-
* Example usage:
361-
* ```typescript
362-
* import { isDevMode } from '@web3nl/vite-plugin-canister-dapp';
363-
*
364-
* if (isDevMode()) {
365-
* console.log('Running in development mode');
366-
* } else {
367-
* console.log('Running in production mode');
368-
* }
369-
* ```
370-
*
371-
* @returns true if running in development mode, false otherwise
372-
*/
373-
export function isDevMode(): boolean {
374-
if (devModeCache !== null) {
375-
return devModeCache;
376-
}
377-
378-
devModeCache = detectDevModeFromOrigin();
379-
return devModeCache;
380-
}
381-
382-
/**
383-
* Infer the canister ID from the current location or fallback to viteDevCanisterId
384-
*
385-
* This function attempts to infer the canister ID from the URL hostname using
386-
* `inferCanisterIdFromLocation` from @web3nl/my-canister-dashboard. This works in:
387-
* - Production: `canister-id.icp0.io` (https only)
388-
* - Local dfx: `canister-id.localhost:port` (http only)
389-
*
390-
* If URL-based inference fails (e.g., when running in a Vite dev server at
391-
* `localhost:5173`), it falls back to the `viteDevCanisterId` configured in the
392-
* Vite plugin.
393-
*
394-
* Example usage:
395-
* ```typescript
396-
* import { inferCanisterId } from '@web3nl/vite-plugin-canister-dapp';
397-
*
398-
* async function initializeAgent() {
399-
* const canisterId = inferCanisterId();
400-
* // Use canisterId to create actor...
401-
* }
402-
* ```
403-
*
404-
* @returns The canister ID as a Principal
405-
* @throws Error if canister ID cannot be inferred from URL and viteDevCanisterId is not configured
406-
*/
407-
export function inferCanisterId(): Principal {
408-
try {
409-
return inferCanisterIdFromLocation();
410-
} catch {
411-
// URL inference failed - only happens in Vite dev server
412-
if (
413-
typeof __VITE_DEV_CANISTER_ID__ !== 'undefined' &&
414-
__VITE_DEV_CANISTER_ID__ !== null
415-
) {
416-
return Principal.fromText(__VITE_DEV_CANISTER_ID__);
417-
}
418-
419-
throw new Error(
420-
'Could not infer canister ID from URL. ' +
421-
'When using Vite dev server, set viteDevCanisterId in plugin config.'
422-
);
423-
}
424-
}
425-
426-
// Cache for environment configuration
427-
let configCache: CanisterDappEnvironmentConfig | null = null;
428-
429-
// Cache for dev mode detection
430-
let devModeCache: boolean | null = null;
431-
432271
function notEmptyString(value: unknown): value is string {
433272
return typeof value === 'string' && value.length > 0;
434273
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import { Principal } from '@dfinity/principal';
2+
import { inferCanisterIdFromLocation } from '@web3nl/my-canister-dashboard';
3+
import type { CanisterDappEnvironmentConfig } from './plugin';
4+
5+
/**
6+
* Default development environment configuration
7+
*/
8+
const DEFAULT_DEV_CONFIG: CanisterDappEnvironmentConfig = {
9+
host: 'http://localhost:8080',
10+
identityProvider: 'http://rdmx6-jaaaa-aaaaa-aaadq-cai.localhost:8080',
11+
};
12+
13+
/**
14+
* Default production environment configuration
15+
*/
16+
const DEFAULT_PROD_CONFIG: CanisterDappEnvironmentConfig = {
17+
host: 'https://icp-api.io',
18+
identityProvider: 'https://identity.internetcomputer.org',
19+
};
20+
21+
// Cache for environment configuration
22+
let configCache: CanisterDappEnvironmentConfig | null = null;
23+
24+
// Cache for dev mode detection
25+
let devModeCache: boolean | null = null;
26+
27+
/**
28+
* Detect if the application is running in development mode based on URL origin
29+
*
30+
* Development mode is detected when the origin:
31+
* - Starts with 'http://' (not https)
32+
* - Contains 'localhost'
33+
* - Contains '127.0.0.1'
34+
*
35+
* This function is used internally by `inferEnvironment()` and `isDevMode()`.
36+
*
37+
* @returns true if running in development mode, false otherwise
38+
*/
39+
function detectDevModeFromOrigin(): boolean {
40+
if (typeof window === 'undefined' || !window.location) {
41+
// SSR or non-browser environment, default to production
42+
return false;
43+
}
44+
45+
const origin = window.location.origin.toLowerCase();
46+
return (
47+
origin.startsWith('http://') ||
48+
origin.includes('localhost') ||
49+
origin.includes('127.0.0.1')
50+
);
51+
}
52+
53+
/**
54+
* Infer the canister dapp environment at runtime based on URL origin
55+
*
56+
* This helper function automatically determines the environment configuration by
57+
* analyzing the current URL origin. It returns the development configuration if
58+
* the origin indicates a development environment (http://, localhost, or 127.0.0.1),
59+
* otherwise it returns the production configuration.
60+
*
61+
* Both configurations are embedded in the build by the Vite plugin, so no network
62+
* requests are needed. This enables building a single WASM that works in all environments.
63+
*
64+
* The result is cached for performance, so subsequent calls will return the cached value.
65+
*
66+
* Example usage:
67+
* ```typescript
68+
* import { inferEnvironment } from '@web3nl/vite-plugin-canister-dapp/runtime';
69+
*
70+
* export function getConfig() {
71+
* const config = inferEnvironment();
72+
* console.log('Running in:', config.host);
73+
* return config;
74+
* }
75+
* ```
76+
*
77+
* @returns The environment configuration (dev or prod based on URL origin)
78+
*/
79+
export function inferEnvironment(): CanisterDappEnvironmentConfig {
80+
if (configCache !== null) {
81+
return configCache;
82+
}
83+
84+
// Detect environment based on URL origin
85+
const isDev = detectDevModeFromOrigin();
86+
87+
// Get the appropriate config from the injected global constants
88+
const config = isDev
89+
? typeof __CANISTER_DAPP_DEV_CONFIG__ !== 'undefined'
90+
? __CANISTER_DAPP_DEV_CONFIG__
91+
: DEFAULT_DEV_CONFIG
92+
: typeof __CANISTER_DAPP_PROD_CONFIG__ !== 'undefined'
93+
? __CANISTER_DAPP_PROD_CONFIG__
94+
: DEFAULT_PROD_CONFIG;
95+
96+
configCache = config;
97+
return config;
98+
}
99+
100+
/**
101+
* Check if the application is running in development mode based on URL origin
102+
*
103+
* This function checks the URL origin to determine if the application is running
104+
* in development mode. Development mode is detected when the origin:
105+
* - Starts with 'http://' (not https)
106+
* - Contains 'localhost'
107+
* - Contains '127.0.0.1'
108+
*
109+
* The result is cached for performance, so subsequent calls will return the cached value.
110+
*
111+
* Example usage:
112+
* ```typescript
113+
* import { isDevMode } from '@web3nl/vite-plugin-canister-dapp/runtime';
114+
*
115+
* if (isDevMode()) {
116+
* console.log('Running in development mode');
117+
* } else {
118+
* console.log('Running in production mode');
119+
* }
120+
* ```
121+
*
122+
* @returns true if running in development mode, false otherwise
123+
*/
124+
export function isDevMode(): boolean {
125+
if (devModeCache !== null) {
126+
return devModeCache;
127+
}
128+
129+
devModeCache = detectDevModeFromOrigin();
130+
return devModeCache;
131+
}
132+
133+
/**
134+
* Infer the canister ID from the current location or fallback to viteDevCanisterId
135+
*
136+
* This function attempts to infer the canister ID from the URL hostname using
137+
* `inferCanisterIdFromLocation` from @web3nl/my-canister-dashboard. This works in:
138+
* - Production: `canister-id.icp0.io` (https only)
139+
* - Local dfx: `canister-id.localhost:port` (http only)
140+
*
141+
* If URL-based inference fails (e.g., when running in a Vite dev server at
142+
* `localhost:5173`), it falls back to the `viteDevCanisterId` configured in the
143+
* Vite plugin.
144+
*
145+
* Example usage:
146+
* ```typescript
147+
* import { inferCanisterId } from '@web3nl/vite-plugin-canister-dapp/runtime';
148+
*
149+
* function initializeAgent() {
150+
* const canisterId = inferCanisterId();
151+
* // Use canisterId to create actor...
152+
* }
153+
* ```
154+
*
155+
* @returns The canister ID as a Principal
156+
* @throws Error if canister ID cannot be inferred from URL and viteDevCanisterId is not configured
157+
*/
158+
export function inferCanisterId(): Principal {
159+
try {
160+
return inferCanisterIdFromLocation();
161+
} catch {
162+
// URL inference failed - only happens in Vite dev server
163+
if (
164+
typeof __VITE_DEV_CANISTER_ID__ !== 'undefined' &&
165+
__VITE_DEV_CANISTER_ID__ !== null
166+
) {
167+
return Principal.fromText(__VITE_DEV_CANISTER_ID__);
168+
}
169+
170+
throw new Error(
171+
'Could not infer canister ID from URL. ' +
172+
'When using Vite dev server, set viteDevCanisterId in plugin config.'
173+
);
174+
}
175+
}

0 commit comments

Comments
 (0)