1"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[70],{274372(i,t,n){var a={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0},o=this&&this.__importDefault||function(_){return _&&_.__esModule?_:{default:_}};Object.defineProperty(t,"__esModule",{value:!0});const e=o(n(531715)),m=n(241737),c=o(n(154e3)),d=o(n(590209)),u=o(n(702523)),p=o(n(452094)),v=o(n(399965)),s={"my-env.bit-env.ts":u.default,"index.ts":c.default,"config/tsconfig.json":d.default,"config/eslintrc.js":p.default,"config/jest.config.js":v.default},l=()=>e.default.createElement(m.FileExplorer,{options:{contentFontSize:13,fileTreeWidth:230,codeHeight:400,isDirOpen:!0,title:"my-org.my-scope/my-env",wordWrap:"off"},files:s,defaultFile:"config/tsconfig.json"});l.__bit_component=a,t.default=l},702523(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`import type { EnvHandler } from '@teambit/envs'; 2import { 3 TypescriptTask, 4 TypescriptConfigWriter, 5 TypescriptCompiler, 6} from '@teambit/typescript.typescript-compiler'; 7import { 8 ESLintLinter,
9 EslintConfigWriter, 10 EslintTask, 11} from '@teambit/defender.eslint-linter'; 12import { ESLint as ESLintLib } from 'eslint'; 13import { JestTask, JestTester } from '@teambit/defender.jest-tester'; 14import typescript from 'typescript'; 15import { Pipeline } from '@teambit/builder'; 16import { ConfigWriterList } from '@teambit/workspace-config-files'; 17import { Compiler } from '@teambit/compiler'; 18import { Tester } from '@teambit/tester'; 19 20export class MyEnv { 21 name = 'my-env'; 22 23 protected tsconfigPath = require.resolve('./config/tsconfig.json'); 24 25 protected jestConfigPath = require.resolve('./config/jest.config'); 26 27 protected eslintConfigPath = require.resolve('./config/eslintrc.js'); 28 29 protected eslintExtensions = ['.ts', '.js']; 30 31 /** 32 * compilation during development 33 * ('bit compile', 'bit watch', 'bit start') 34 */ 35 compiler(): EnvHandler<Compiler> { 36 return TypescriptCompiler.from({ 37 tsconfig: this.tsconfigPath, 38 typescript, 39 }); 40 } 41 42 /** 43 * test during development. 44 * ('bit test') 45 */ 46 tester(): EnvHandler<Tester> { 47 return JestTester.from({ 48 jest: require.resolve('jest'), 49 config: this.jestConfigPath, 50 }); 51 } 52 53 /** 54 * lint during development. 55 * ('bit lint') 56 */ 57 linter() { 58 return ESLintLinter.from({ 59 tsconfig: this.tsconfigPath, 60 eslint: ESLintLib, 61 configPath: this.eslintConfigPath, 62 }); 63 } 64 65 /** 66 * component build pipeline. 67 * ('bit build', 'bit snap', 'bit tag') 68 */ 69 build() { 70 return Pipeline.from([ 71 TypescriptTask.from({ 72 tsconfig: this.tsconfigPath, 73 typescript, 74 }), 75 EslintTask.from({ 76 tsconfig: this.tsconfigPath, 77 eslint: ESLintLib, 78 configPath: this.eslintConfigPath, 79 }), 80 JestTask.from({ 81 config: this.jestConfigPath, 82 jest: require.resolve('jest'), 83 }), 84 ]); 85 } 86 87 /** 88 * generate configuration files for better IDE support 89 * ('bit ws-config write', 'bit new') 90 */ 91 workspaceConfig(): ConfigWriterList { 92 return ConfigWriterList.from([ 93 TypescriptConfigWriter.from({ 94 tsconfig: this.tsconfigPath, 95 }), 96 EslintConfigWriter.from({ 97 configPath: this.eslintConfigPath, 98 tsconfig: this.tsconfigPath, 99 }), 100 ]); 101 } 102} 103 104export default new MyEnv();`},452094(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`module.exports = { 105// ... 106 rules: { 107 'import/no-nodejs-modules': 'error', 108 }, 109};`},154e3(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default="export { MyEnv } from './my-env.bit-env';"},399965(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`module.exports = { 110 // ... 111 testEnvironment: require.resolve('jest-environment-jsdom'), 112};`},590209(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`{ 113 // ... 114 "compilerOptions": { 115 "target": "es2020", 116 "lib": ["dom", "dom.Iterable"], 117 // ... 118 } 119}`},468631(i,t,n){var a={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0},o=this&&this.__importDefault||function(l){return l&&l.__esModule?l:{default:l}};Object.defineProperty(t,"__esModule",{value:!0});const e=o(n(531715)),m=n(241737),c=o(n(187175)),d=o(n(842352)),u=o(n(436020)),v={"my-env.bit-env.ts":o(n(677124)).default,"index.ts":c.default,"config/tsconfig.modern.json":d.default,"config/tsconfig.legacy.json":u.default},s=()=>e.default.createElement(m.FileExplorer,{options:{contentFontSize:13,fileTreeWidth:230,codeHeight:400,isDirOpen:!0,title:"my-org.my-scope/my-env",wordWrap:"off"},files:v,defaultFile:"my-env.bit-env.ts"});s.__bit_component=a,t.default=s},677124(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0}
119;Object.defineProperty(t,"__esModule",{value:!0}),t.default=`import type { EnvHandler } from '@teambit/envs'; 120import { 121 TypescriptTask, 122 TypescriptCompiler, 123} from '@teambit/typescript.typescript-compiler'; 124import typescript from 'typescript'; 125import { Pipeline } from '@teambit/builder'; 126import { Compiler } from '@teambit/compiler'; 127import { PackageGenerator } from '@teambit/pkg'; 128 129export class MyEnv { 130 name = 'my-env'; 131 132 protected modernTsconfigPath = require.resolve( 133 './config/tsconfig.modern.json' 134 ); 135 136 protected legacyTsconfigPath = require.resolve( 137 './config/tsconfig.legacy.json' 138 ); 139 140 packageJson = { 141 main: 'dist/esm/{main}.js', 142 exports: { 143 require: './dist/cjs/index.js', 144 import: './dist/esm/index.js', 145 }, 146 types: '{main}.ts', 147 type: 'module', 148 }; 149 150 package() { 151 return PackageGenerator.from({ 152 packageJson: this.packageJson, 153 // ... 154 }); 155 } 156 157 /** 158 * compilation during development 159 * ('bit compile', 'bit watch', 'bit start') 160 */ 161 compiler(): EnvHandler<Compiler> { 162 return TypescriptCompiler.from({ 163 tsconfig: this.modernTsconfigPath, 164 typescript, 165 }); 166 } 167 168 /** 169 * component build pipeline. 170 * ('bit build', 'bit snap', 'bit tag') 171 */ 172 build() { 173 return Pipeline.from([ 174 TypescriptTask.from({ 175 tsconfig: this.modernTsconfigPath, 176 typescript, 177 }), 178 TypescriptTask.from({ 179 tsconfig: this.legacyTsconfigPath, 180 typescript, 181 }), 182 ]); 183 } 184} 185 186export default new MyEnv();`},187175(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default="export { MyEnv } from './my-env.bit-env';"},436020(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`{ 187 // ... 188 "compilerOptions": { 189 "target": "ES5", 190 "module": "CommonJS", 191 "lib": ["DOM", "ES5"], 192 "outDir": "dist/cjs", 193 // ... 194 } 195}`},842352(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`{ 196 // ... 197 "compilerOptions": { 198 "target": "es2020", 199 "module": "esnext", 200 "lib": ["DOM", "ES2020"], 201 "outDir": "dist/esm", 202 // ... 203 } 204}`},35485(i,t,n){var a={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0},o=this&&this.__importDefault||function(s){return s&&s.__esModule?s:{default:s}};Object.defineProperty(t,"__esModule",{value:!0});const e=o(n(531715)),m=n(241737),c=o(n(242821)),d=o(n(71506)),u=o(n(644006)),p={"my-env.bit-env.ts":d.default,"index.ts":c.default,"env.jsonc":u.default},v=()=>e.default.createElement(m.FileExplorer,{options:{contentFontSize:13,fileTreeWidth:230,codeHeight:400,isDirOpen:!0,title:"my-org.my-scope/my-env",wordWrap:"off"},files:p,defaultFile:"env.jsonc"});v.__bit_component=a,t.default=v},71506(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`// imports ... 205export class MyEnv { 206 name = 'my-react-env'; 207 // ... 208 209} 210 211export default new MyEnv();`},644006(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`{ 212 "policy": { 213 "peers": [ 214 { 215 "name": "react", 216 /** 217 * install this version as a regular dependency of the env. 218 * this is because, peer dependencies are always installed 219 * as regular dependencies of the components' "host". 220 * this can be the env, when previewing components, or an app consuming the component 221 * */ 222 "version": "^17.0.0", 223 /** 224 * configure components maintained by this env with this range as their peer dependency 225 * */ 226 "supportedRange": "^16.8.0 || ^17.0.0" 227 }, 228 { 229 "name": "react-dom", 230 "version": "^17.0.0", 231 "supportedRange": "^17.0.0 || ^18.0.0" 232 } 233 ] 234 } 235}`},242821(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0}
235;Object.defineProperty(t,"__esModule",{value:!0}),t.default="export { MyEnv } from './my-env.bit-env';"},505585(i,t,n){var a={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0},o=this&&this.__importDefault||function(l){return l&&l.__esModule?l:{default:l}};Object.defineProperty(t,"__esModule",{value:!0});const e=o(n(531715)),m=n(241737),c=o(n(845425)),d=o(n(354066)),u=o(n(743246)),p=o(n(682287)),v={"my-env.bit-env.ts":u.default,"index.ts":c.default,"config/tsconfig.json":d.default,"mounter.tsx":p.default},s=()=>e.default.createElement(m.FileExplorer,{options:{contentFontSize:13,fileTreeWidth:230,codeHeight:400,isDirOpen:!0,title:"my-org.my-scope/my-env",wordWrap:"off"},files:v,defaultFile:"my-env.bit-env.ts"});s.__bit_component=a,t.default=s},743246(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`import type { EnvHandler } from '@teambit/envs'; 236import type { Preview } from '@teambit/preview'; 237import { ReactPreview } from '@teambit/preview.react-preview'; 238 239export class MyEnv { 240 /** 241 * use the react renderer to render component previews, 242 * and wrap each preview with a theme. 243 */ 244 preview(): EnvHandler<Preview> { 245 return ReactPreview.from({ 246 mounter: require.resolve('./preview/mounter'), 247 // ... 248 }); 249 } 250} 251 252export default new MyEnv();`},845425(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default="export { MyEnv } from './my-env.bit-env';"},682287(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`import React from 'react'; 253/* react renderer */ 254import { createMounter } from '@teambit/react.mounter'; 255/* theme */ 256import { AcmeTheme } from '@bitdesign/basic-react.acme-theme'; 257 258/** 259 * provide your component compositions (preview) with the context they need to run. 260 */ 261export function MyReactProvider({ children }: { children: React.ReactNode }) { 262 return <AcmeTheme>{children}</AcmeTheme>; 263} 264 265export default createMounter(MyReactProvider) as any;`},354066(i,t){var n={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0};Object.defineProperty(t,"__esModule",{value:!0}),t.default=`{ 266 // ... 267 "compilerOptions": { 268 "target": "es2020", 269 "lib": ["dom", "dom.Iterable"], 270 // ... 271 } 272}`},823358(i,t,n){var a={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0},o=this&&this.__importDefault||function(p){return p&&p.__esModule?p:{default:p}};Object.defineProperty(t,"__esModule",{value:!0}),t.EnvNamesAndIcons=t.CoverImage=void 0;const e=o(n(531715)),m=n(241040),c=o(n(430212)),d=()=>e.default.createElement(m.Image,{className:c.default.image,src:"https://static.bit.dev/Community/images/component-runtimes.jpeg"});d.__bit_component=a,t.CoverImage=d;const u=()=>e.default.createElement(m.Image,{className:c.default.image,src:"https://static.bit.dev/Community/images/env-names-screenshot.png"});u.__bit_component=a,t.EnvNamesAndIcons=u},264454(i,t,n){var a={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0},o=this&&this.__importDefault||function(m){return m&&m.__esModule?m:{default:m}};Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.RuntimeEnvsForComponents=void 0;var e=n(974659);Object.defineProperty(t,"RuntimeEnvsForComponents",{enumerable:!0,get:function(){return o(e).default}}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return o(e).default}})},974659(i,t,n){var a={id:"teambit.blog-content/[email protected]",homepage:"https://bit.cloud/teambit/blog-content/runtime-envs-for-components",exported:!0}
272;Object.defineProperty(t,"__esModule",{value:!0}),t.default=x;var o=s(n(531715)),e=n(437910),m=n(823358),c=s(n(274372)),d=s(n(35485)),u=s(n(468631)),p=s(n(505585)),v=["components"];function s(r){return r&&r.__esModule?r:{default:r}}s.__bit_component=a;function l(){return l=Object.assign?Object.assign.bind():function(r){for(var b=1;b<arguments.length;b++){var h=arguments[b];for(var f in h)Object.prototype.hasOwnProperty.call(h,f)&&(r[f]=h[f])}return r},l.apply(this,arguments)}l.__bit_component=a;function _(r,b){if(r==null)return{};var h=w(r,b),f,g;if(Object.getOwnPropertySymbols){var y=Object.getOwnPropertySymbols(r);for(g=0;g<y.length;g++)f=y[g],!(b.indexOf(f)>=0)&&(!Object.prototype.propertyIsEnumerable.call(r,f)||(h[f]=r[f]))}return h}_.__bit_component=a;function w(r,b){if(r==null)return{};var h={},f=Object.keys(r),g,y;for(y=0;y<f.length;y++)g=f[y],!(b.indexOf(g)>=0)&&(h[g]=r[g]);return h}w.__bit_component=a;var P={},E="wrapper";function x(r){var b=r.components,h=_(r,v);return(0,e.mdx)(E,l({},P,h,{components:b,mdxType:"MDXLayout"}),(0,e.mdx)(m.CoverImage,{mdxType:"CoverImage"}),(0,e.mdx)("h2",null,"Introduction"),(0,e.mdx)("p",null,`Runtime environments are normally mentioned in the context of programs or applications rather than components. 273However, the term can be extended to fit components as well. Runtime environments are the context that a component requires for it to function properly. 274The more specific that context is, the less compatible the component is with other components and applications.`),(0,e.mdx)("p",null,`It's useful to think of runtime environments as being composed of "onion layers", where the inner layers are dependent on the outer layers.`),(0,e.mdx)("p",null,"For example, think of a simple client-side React component. What is its runtime environment?"),(0,e.mdx)("p",null,"On the very outer layer, we have the JavaScript engine, then the browser (the browser API), and finally, the React and React DOM libraries."),(0,e.mdx)("blockquote",null,(0,e.mdx)("p",{parentName:"blockquote"},"We can ignore other layers, like the operating system and the CPU architecture, since they are less relevant to JavaScript and Web (although, not completely irrelevant).")),(0,e.mdx)("h2",null,"Component compatibility based on runtime environments"),(0,e.mdx)("p",null,"In the example above, the React component requires a browser, a React library, and a React DOM library."),(0,e.mdx)("p",null,"A component that requires ",(0,e.mdx)("em",{parentName:"p"},"some of these runtime layers"),", like a function that updates the browser local storage, would still be ",(0,e.mdx)("strong",{parentName:"p"},"compatible"),` with the client-side React component. 275Both components would be able to integrate into a single application, running as a single process. Furthermore, depending on the components' purpose and API, the two might even be interchangeable.`),(0,e.mdx)("p",null,"In contrast, a component that requires ",(0,e.mdx)("em",{parentName:"p"},"different runtime layers that are mutually exclusive"),", for instance, one that needs the NodeJS runtime to perform ",(0,e.mdx)("inlineCode",{parentName:"p"},"read"),"/",(0,e.mdx)("inlineCode",{parentName:"p"},"write"),` operations in the filesystem, would not be able to integrate with the client-side React component into a single application, running as a single process. 276The two components would be `,(0,e.mdx)("strong",{parentName:"p"},"incompatible"),", as they require a different context for their execution."),(0,e.mdx)("p",null,"When building Bit components, we need to consider the runtime environment of the component; Define it, implement the component accordingly, and inform its potential consumers, so they would be able tell where and how to use it."),(0,e.mdx)("blockquote",null,(0,e.mdx)("p",{parentName:"blockquote"},"There are several ways to broaden the compatibility of a component, and we'll discuss some of them later in this post.")),(0,e.mdx)("h2",null,"Using dev environments to define runtime environments"),(0,e.mdx)("p",null,`A component's runtime environment is defined via the component's development environment. 277`,(0,e.mdx)("a",{parentName:"p",href:"https://bit.dev/reference/envs/create-env"},"Component development environments")," or 'envs', are absent when the component is executed in runtime since, as their name suggests, they are only used during development."),(0,e.mdx)("p",null,"However, configuring the ",(0,e.mdx)("strong",{parentName:"p"},"proper tools and settings")," in the component's development environment, ensures that a component is able to function in its target runtime environment. This is done on four levels."),(0,e.mdx)("h3",null,"1. Runtime environment-relevant feedback during development"),(0,e.mdx)("p",null,"Dev tools should be configured to provide relevant feedback during the component's development. For instance, if our component requires a browser, we would configure its env's Typescript compiler with the ",(0,e.mdx)("inlineCode",{parentName:"p"},"lib")," option set to ",(0,e.mdx)("inlineCode",{parentName:"p"},'"DOM"'),", so our dev tools and IDE would know that the component is allowed to use the browser API."),(0,e.mdx)("p",null,"Other examples include configuring the ESLint plugin to prevent the use of NodeJS-specific APIs, or configuring the Jest test runner to run the tests in a browser-like environment."),(0,e.mdx)(c.default,{mdxType:"BrowserEnv"}),(0,e.mdx)("br",null),(0,e.mdx)("div",{className:"admonition admonition-info alert alert--info"}
277,(0,e.mdx)("div",{parentName:"div",className:"admonition-heading"},(0,e.mdx)("h5",{parentName:"div"},(0,e.mdx)("span",{parentName:"h5",className:"admonition-icon"},(0,e.mdx)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,e.mdx)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"Runtime agnostic components")),(0,e.mdx)("div",{parentName:"div",className:"admonition-content"},(0,e.mdx)("p",{parentName:"div"},`In some case, components should be runtime-agnostic (i.e, depend only on a generic Javascript engine). One example of that are entity components which provide type definitions, schema validation, and utility functions for the manipulation of a certain type of data. 278They are often used as a "contract" between backend services and frontend applications. In this case, we want our dev tools to prevent us from using APIs that are not available in the target runtime environment.`),(0,e.mdx)("p",{parentName:"div"},(0,e.mdx)("em",{parentName:"p"},"See an example of a ",(0,e.mdx)("a",{parentName:"em",href:"https://bit.cloud/bits-and-pieces/dev/envs/any-runtime-ts-env/~code/any-runtime-ts-env.bit-env.ts"},"TS runtime agnostic env"),".")),(0,e.mdx)("p",{parentName:"div"},(0,e.mdx)("em",{parentName:"p"},"See an example of ",(0,e.mdx)("a",{parentName:"em",href:"https://bit.cloud/learnbit-react/data-fetching/entities/brewery/~code/brewery.ts"},"a generic entity"),"."),` 279`,(0,e.mdx)("em",{parentName:"p"},"See an example of ",(0,e.mdx)("a",{parentName:"em",href:"https://bit.cloud/bits-and-pieces/article-submission/entities/article-submission-scheme/~code/article-submission-scheme.ts"},"a Medium article submission entity")," (implemented with ",(0,e.mdx)("a",{parentName:"em",href:"https://zod.dev/"},"Zod"),")")))),(0,e.mdx)("h3",null,"2. Build artifacts that are compatible with the target runtime environment"),(0,e.mdx)("p",null,"The component build should generate artifacts that are compatible with the target runtime environment. For instance, if the runtime environment we're aiming for is a ",(0,e.mdx)("em",{parentName:"p"},"modern")," browser, we would set the ",(0,e.mdx)("inlineCode",{parentName:"p"},"target")," option to ",(0,e.mdx)("inlineCode",{parentName:"p"},"es6")," or higher (see the ",(0,e.mdx)("inlineCode",{parentName:"p"},"tsconfig.json")," file in the demo env above)."),(0,e.mdx)("h3",null,'3. Peer dependencies that make up the "inner layers" of the runtime environment'),(0,e.mdx)("p",null,(0,e.mdx)("a",{parentName:"p",href:"https://bit.dev/reference/dependencies/dependency-policies#peer-dependencies"},(0,e.mdx)("strong",{parentName:"a"},"Peer dependencies")),` are a crucial part of defining the component's runtime environment. 280A peer dependency is a dependency that is expected to be provided by the "host" or app consuming the component, rather than the component itself. 281Remember that, from the perspective of a component, parts of the consuming app can be considered as parts of its runtime environment. 282That happens when these parts function as the context that the component requires for it to function properly.`),(0,e.mdx)("p",null,"For example, a React 17 component will probably have the following dependencies configured in its env's ",(0,e.mdx)("inlineCode",{parentName:"p"},"env.jsonc")," file:"),(0,e.mdx)(d.default,{mdxType:"PeersEnv"}),(0,e.mdx)("br",null),(0,e.mdx)("p",null,`Note that peer dependencies are not only for framework libraries, but also for other components and packages that are expected to be provided by the consuming app. 283This can be a theme, a routing system, a global state, or any other package that is expected to be provided by the consuming app.`),(0,e.mdx)("h3",null,"4. Component previews that support the relevant runtime environment"),(0,e.mdx)("p",null,`Component previews are useful part of the component's development, testing, and documentation. 284A 'preview' dev service (configured in the component's env) should provide the same context that the component requires for it to function properly.`),(0,e.mdx)("p",null,`For instance, React components should use a preview that runs React for rendering.
285If they requires additional context, like a theme or a routing system, this should be provided as well.`),(0,e.mdx)(p.default,{mdxType:"ThemeEnv"}),(0,e.mdx)("h2",null,"Declaring the runtime environment of a component"),(0,e.mdx)("p",null,"A component's runtime environment should be apparent to its consumers by looking at the component's env (development environment)."),(0,e.mdx)("p",null,"An env should have a component ID that informs of the runtime environment its components are compatible with. For instance, the component ID of an env for React 17 components, should be ",(0,e.mdx)("inlineCode",{parentName:"p"},"my-org.my-scope/react-17"),`. 286The same is true for the env's `,(0,e.mdx)("inlineCode",{parentName:"p"},"icon")," and ",(0,e.mdx)("inlineCode",{parentName:"p"},"name")," properties."),(0,e.mdx)("pre",null,(0,e.mdx)("code",{parentName:"pre",className:"language-ts"},`/** 287 * @filename: react-17-env.bit-env.ts 288 * @component-id: my-org.my-scope/react-17 289 * */ 290 291export class React17Env { 292 name = 'react-17'; 293 icon = 'https://path/to/icon/react.svg'; 294} 295`)),(0,e.mdx)("p",null,"The env icon, name and component ID are displayed in the UI, and are used by Bit's search engine to match components with their consumers."),(0,e.mdx)(m.EnvNamesAndIcons,{mdxType:"EnvNamesAndIcons"}),(0,e.mdx)("h2",null,"Broadening the runtime environment of a component"),(0,e.mdx)("p",null,"The main topic for this blog post is not how to increase compatibility and reusability of components, but it's worth mentioning that there are several ways to do so."),(0,e.mdx)("h3",null,"1. Generic envs over specific envs"),(0,e.mdx)("p",null,`The more generic the env is, the broader the range of runtime environments its components are compatible with. 296For instance, setting your client-side component with a generic env, like the `,(0,e.mdx)("a",{parentName:"p",href:"https://bit.dev/docs/html-overview"},"HTML env")," (when possible) will make it clear to its consumers that it is compatible with a wide range of frontend applications, and is not limited to a specific framework or runtime environment."),(0,e.mdx)("h3",null,"2. Fallbacks"),(0,e.mdx)("p",null,`In some cases, it makes sense for a component to have fallbacks for more generic runtime environments. 297For instance, a NextJS component that requires the NextJS runtime, can have a fallback which would allow it to be used in a wide range of React applications.`),(0,e.mdx)("p",null,"In the example below, a NextJS component uses the NextJS image component only if it's available in the runtime environment."),(0,e.mdx)("pre",null,(0,e.mdx)("code",{parentName:"pre",className:"language-tsx"},`/* @filename: {COMPONENT_DIRECTORY}/card.tsx */ 298 299/** 300 * This component utilizes the image optimization feature, provided by NextJS. 301 */ 302import Image from 'next/image'; 303 304export function Card({ info }) { 305 const isNextJS = process.env.FRAMEWORK === 'nextjs'; 306 return ( 307 <article key={info.id}> 308 <h5>{info.name}</h5> 309 <Image 310 src={info.image} 311 alt={info.name} 312 fill 313 /* disable NextJS image optimization in non-NextJS React environments */ 314 unoptimized={!isNextJS} 315 /> 316 </article> 317 ); 318} 319`)),(0,e.mdx)("h3",null,"3. Dependency injection for runtime-specific APIs"),(0,e.mdx)("p",null,'Using dependency injection a component can implement a "placeholder" for a runtime-specific API, that allows the consuming app to provide the actual implementation.'),(0,e.mdx)("p",null,`For example, a React component might use a different routing system, based on the app that consumes it. 320In this case, the `,(0,e.mdx)("inlineCode",{parentName:"p"},"Link")," component needs to implement a different logic that would use the routing system provided by the consuming app."),(0,e.mdx)("p",null,"For an example, see this ",(0,e.mdx)("a",{parentName:"p",href:"https://bit.cloud/learnbit/base-react/navigation/my-router-adapter"},"React Router Adapter")),(0,e.mdx)("h3",null,"4. Multiple build outputs"),(0,e.mdx)("p",null,`A component can have multiple build outputs, each targeting a different runtime environment. 321For example, the following env has in its build pipeline two compilation steps, one for modern browsers and one for legacy browsers.`),(0,e.mdx)(u.default,{mdxType:"LegacyModernEnv"}))}x.__bit_component=a,x.isMDXComponent=!0},430212(i,t,n){n.r(t),n.d(t,{default:()=>a});const a={image:"runtime-envs-for-components_image__xbS2D"}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.