Skip to content

Commit ab6dff1

Browse files
authored
feat(config): env (#2732)
1 parent 26485db commit ab6dff1

20 files changed

+122
-4
lines changed

src/app-data/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,6 @@ export const BUILD: BuildConditionals = {
8383
attachStyles: true,
8484
};
8585

86+
export const Env = {};
87+
8688
export const NAMESPACE = /* default */ 'app' as string;

src/client/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ export * from './client-style';
77
export * from './client-task-queue';
88
export * from './client-build';
99
export * from '@runtime';
10-
export { BUILD, NAMESPACE } from '@app-data';
10+
export { BUILD, NAMESPACE, Env } from '@app-data';

src/compiler/bundle/app-data-plugin.ts

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export const appDataPlugin = (
5757
const s = new MagicString(``);
5858
appendNamespace(config, s);
5959
appendBuildConditionals(config, build, s);
60+
appendEnv(config, s);
6061
return s.toString();
6162
}
6263
return null;
@@ -149,6 +150,10 @@ const appendBuildConditionals = (config: d.Config, build: d.BuildConditionals, s
149150
s.append(`export const BUILD = /* ${config.fsNamespace} */ { ${builData} };\n`);
150151
};
151152

153+
const appendEnv = (config: d.Config, s: MagicString) => {
154+
s.append(`export const Env = /* ${config.fsNamespace} */ ${JSON.stringify(config.env) };\n`);
155+
};
156+
152157
const appendNamespace = (config: d.Config, s: MagicString) => {
153158
s.append(`export const NAMESPACE = '${config.fsNamespace}';\n`);
154159
};

src/compiler/config/validate-config.ts

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ export const validateConfig = (userConfig?: Config) => {
7575
const err = buildError(diagnostics);
7676
err.messageText = `config.hashedFileNameLength cannot be more than ${MAX_HASHED_FILENAME_LENTH} characters`;
7777
}
78+
if (!config.env) {
79+
config.env = {};
80+
}
7881

7982
// get a good namespace
8083
validateNamespace(config, diagnostics);

src/compiler/transformers/update-stencil-core-import.ts

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const KEEP_IMPORTS = new Set([
6161
'setMode',
6262
'getMode',
6363
'Build',
64+
'Env',
6465
'Host',
6566
'Fragment',
6667
'getAssetPath',

src/declarations/stencil-private.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2213,6 +2213,7 @@ export interface JestEnvironmentGlobal {
22132213
fullName: string;
22142214
testPath: string;
22152215
};
2216+
env: {[prop: string]: string};
22162217
screenshotDescriptions: Set<string>;
22172218
}
22182219

@@ -2224,6 +2225,7 @@ export interface E2EProcessEnv {
22242225
STENCIL_SCREENSHOT_SERVER?: string;
22252226

22262227
__STENCIL_EMULATE_CONFIGS__?: string;
2228+
__STENCIL_ENV__?: string;
22272229
__STENCIL_EMULATE__?: string;
22282230
__STENCIL_BROWSER_URL__?: string;
22292231
__STENCIL_APP_SCRIPT_URL__?: string;

src/declarations/stencil-public-compiler.ts

+5
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ export interface StencilConfig {
196196
*/
197197
taskQueue?: 'async' | 'immediate' | 'congestionAsync';
198198

199+
/**
200+
* Provide a object of key/values accessible within the app, using the `Env` object.
201+
*/
202+
env?: {[prop: string]: string | undefined};
203+
199204
globalScript?: string;
200205
srcIndexHtml?: string;
201206
watch?: boolean;

src/declarations/stencil-public-runtime.ts

+5
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ export interface UserBuildConditionals {
178178
*/
179179
export declare const Build: UserBuildConditionals;
180180

181+
/**
182+
* The `Env` object provides access to the "env" object declared in the project's `stencil.config.ts`.
183+
*/
184+
export declare const Env: {[prop: string]: string | undefined};
185+
181186
/**
182187
* The `@Component()` decorator is used to provide metadata about the component class.
183188
* https://stenciljs.com/docs/component

src/hydrate/platform/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export const Build: d.UserBuildConditionals = {
140140
export const styles: d.StyleMap = new Map();
141141
export const modeResolutionChain: d.ResolutionHandler[] = [];
142142

143-
export { BUILD, NAMESPACE } from '@app-data';
143+
export { BUILD, NAMESPACE, Env } from '@app-data';
144144
export { hydrateApp } from './hydrate-app';
145145

146146
export {

src/internal/stencil-core/index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export {
3535
forceUpdate,
3636
h,
3737
Host,
38+
Env,
3839
Listen,
3940
Method,
4041
Prop,

src/runtime/test/globals.spec.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Build } from '@stencil/core';
1+
import { Component, Build, Env } from '@stencil/core';
22
import { newSpecPage } from '@stencil/core/testing';
33

44
describe('globals', () => {
@@ -37,6 +37,11 @@ describe('globals', () => {
3737
expect(Build.isTesting).toBe(true);
3838
});
3939

40+
41+
it('Env is defined', () => {
42+
expect(Env).toEqual({});
43+
});
44+
4045
describe('globals/prototypes', () => {
4146
let page: any;
4247
beforeEach(async () => {

src/testing/jest/jest-runner.ts

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export async function runJest(config: d.Config, env: d.E2EProcessEnv) {
1010
// set all of the emulate configs to the process.env to be read later on
1111
const emulateConfigs = getEmulateConfigs(config.testing, config.flags);
1212
env.__STENCIL_EMULATE_CONFIGS__ = JSON.stringify(emulateConfigs);
13+
env.__STENCIL_ENV__ = JSON.stringify(config.env);
1314

1415
if (config.flags.ci || config.flags.e2e) {
1516
env.__STENCIL_DEFAULT_TIMEOUT__ = '30000';

src/testing/jest/jest-setup-test-framework.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type * as d from '@stencil/core/internal';
2-
import { BUILD } from '@app-data';
2+
import { BUILD, Env } from '@app-data';
33
import { expectExtend } from '../matchers';
44
import { setupGlobal, teardownGlobal } from '@stencil/core/mock-doc';
55
import { setupMockFetch } from '../mock-fetch';
@@ -55,4 +55,8 @@ export function jestSetupTestFramework() {
5555
jest.setTimeout(time * 1.5);
5656
jasmine.DEFAULT_TIMEOUT_INTERVAL = time;
5757
}
58+
if (typeof env.__STENCIL_ENV__ === 'string') {
59+
const stencilEnv = JSON.parse(env.__STENCIL_ENV__);
60+
Object.assign(Env, stencilEnv);
61+
}
5862
}

src/testing/platform/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { Build } from './testing-build';
2+
export { Env } from '@app-data';
23
export { consoleDevError, consoleDevInfo, consoleDevWarn, consoleError } from './testing-log';
34
export {
45
Context,

test/end-to-end/src/components.d.ts

+13
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export namespace Components {
2626
}
2727
interface ElementCmp {
2828
}
29+
interface EnvData {
30+
}
2931
interface EventCmp {
3032
"methodThatFiresEventWithOptions": () => Promise<void>;
3133
"methodThatFiresMyDocumentEvent": () => Promise<void>;
@@ -112,6 +114,12 @@ declare global {
112114
prototype: HTMLElementCmpElement;
113115
new (): HTMLElementCmpElement;
114116
};
117+
interface HTMLEnvDataElement extends Components.EnvData, HTMLStencilElement {
118+
}
119+
var HTMLEnvDataElement: {
120+
prototype: HTMLEnvDataElement;
121+
new (): HTMLEnvDataElement;
122+
};
115123
interface HTMLEventCmpElement extends Components.EventCmp, HTMLStencilElement {
116124
}
117125
var HTMLEventCmpElement: {
@@ -187,6 +195,7 @@ declare global {
187195
"dom-interaction": HTMLDomInteractionElement;
188196
"dom-visible": HTMLDomVisibleElement;
189197
"element-cmp": HTMLElementCmpElement;
198+
"env-data": HTMLEnvDataElement;
190199
"event-cmp": HTMLEventCmpElement;
191200
"import-assets": HTMLImportAssetsElement;
192201
"listen-cmp": HTMLListenCmpElement;
@@ -221,6 +230,8 @@ declare namespace LocalJSX {
221230
}
222231
interface ElementCmp {
223232
}
233+
interface EnvData {
234+
}
224235
interface EventCmp {
225236
"onMy-event-with-options"?: (event: CustomEvent<{ mph: number }>) => void;
226237
"onMyDocumentEvent"?: (event: CustomEvent<any>) => void;
@@ -264,6 +275,7 @@ declare namespace LocalJSX {
264275
"dom-interaction": DomInteraction;
265276
"dom-visible": DomVisible;
266277
"element-cmp": ElementCmp;
278+
"env-data": EnvData;
267279
"event-cmp": EventCmp;
268280
"import-assets": ImportAssets;
269281
"listen-cmp": ListenCmp;
@@ -289,6 +301,7 @@ declare module "@stencil/core" {
289301
"dom-interaction": LocalJSX.DomInteraction & JSXBase.HTMLAttributes<HTMLDomInteractionElement>;
290302
"dom-visible": LocalJSX.DomVisible & JSXBase.HTMLAttributes<HTMLDomVisibleElement>;
291303
"element-cmp": LocalJSX.ElementCmp & JSXBase.HTMLAttributes<HTMLElementCmpElement>;
304+
"env-data": LocalJSX.EnvData & JSXBase.HTMLAttributes<HTMLEnvDataElement>;
292305
"event-cmp": LocalJSX.EventCmp & JSXBase.HTMLAttributes<HTMLEventCmpElement>;
293306
"import-assets": LocalJSX.ImportAssets & JSXBase.HTMLAttributes<HTMLImportAssetsElement>;
294307
"listen-cmp": LocalJSX.ListenCmp & JSXBase.HTMLAttributes<HTMLListenCmpElement>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { newE2EPage } from '@stencil/core/testing';
2+
3+
describe('build-data e2e', () => {
4+
it('should navigate to the index.html page w/out url searchParams', async () => {
5+
// create a new puppeteer page
6+
// and go to the root webpage
7+
const page = await newE2EPage({
8+
html: `<build-data></build-data>`,
9+
});
10+
const element = await page.find('build-data');
11+
expect(element).toEqualHtml(`
12+
<build-data custom-hydrate-flag="">
13+
<p>isDev: true</p>
14+
<p>isBrowser: true</p>
15+
<p>isTesting: true</p>
16+
</build-data>
17+
`);
18+
});
19+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { EnvData } from './env-data';
2+
import { newSpecPage } from '@stencil/core/testing';
3+
4+
5+
describe('env-data', () => {
6+
7+
it('should be a test', async () => {
8+
const {root} = await newSpecPage({
9+
components: [EnvData],
10+
html: `<env-data></env-data>`
11+
});
12+
expect(root).toEqualHtml(`
13+
<env-data>
14+
<p>foo: bar</p>
15+
<p>HOST: example.com</p>
16+
</env-data>
17+
`);
18+
});
19+
20+
});
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Component, h, Env, Host } from '@stencil/core';
2+
3+
4+
@Component({
5+
tag: 'env-data'
6+
})
7+
export class EnvData {
8+
9+
render() {
10+
return (
11+
<Host>
12+
<p>foo: {Env.foo}</p>
13+
<p>HOST: {Env.HOST}</p>
14+
</Host>
15+
);
16+
}
17+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# env-data
2+
3+
4+
5+
<!-- Auto Generated Below -->
6+
7+
8+
----------------------------------------------
9+
10+
*Built with [StencilJS](https://stenciljs.com/)*

test/end-to-end/stencil.config.ts

+4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ export const config: Config = {
5555
initialValue: '0',
5656
hydratedValue: '1',
5757
},
58+
env: {
59+
'foo': 'bar',
60+
'HOST': 'example.com'
61+
},
5862
enableCache: false,
5963
hashFileNames: false,
6064
buildEs5: 'prod',

0 commit comments

Comments
 (0)