elfennol/env-to-js-symfony-bundle
Composer 安装命令:
composer require elfennol/env-to-js-symfony-bundle
包简介
Inject Symfony .env variables into the browser at runtime via typed script tags
README 文档
README
Inject Symfony .env variables into the browser at runtime, via <script type="application/json"> tags read by the @elfennol/env-to-js TypeScript package.
BEFORE build(staging) → app.staging.js ← rebuild required for each environment
build(prod) → app.prod.js
AFTER build() → app.js ← one artifact, promoted as-is
On each request, Symfony adds to the HTML:
<script type="application/json" id="rc-app">{"apiBaseUrl":"https://api.example.com"}</script>
The problem
In a Symfony + JavaScript application, variables from .env often need to reach the browser (API URLs, third-party keys, feature flags, etc.). The common solution is to bake them in at build time via DefinePlugin (Webpack) or define (Vite).
Consequences:
- The build artifact is tied to one environment — promoting from staging to prod requires a full rebuild
- Rotating a key or changing config requires a full frontend rebuild and redeployment
- Frontend variables and Symfony
.envbecome two separate systems to maintain
The solution
env-to-js lets Symfony inject .env variables into the HTML at runtime, as typed <script type="application/json"> tags read by a zero-dependency TypeScript reader.
Installation
composer require elfennol/env-to-js-symfony-bundle npm install @elfennol/env-to-js
Setup
1. Add the Twig block to your base template
{# templates/base.html.twig #} {% block env_to_js %} {{ env_to_js_scripts()|raw }} {% endblock %}
2. Create a provider
// src/Config/AppConfigProvider.php namespace App\Config; use Elfennol\EnvToJs\ConfigProviderInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\Request; final class AppConfigProvider implements ConfigProviderInterface { public function __construct( #[Autowire(env: 'API_BASE_URL')] private string $apiBaseUrl, #[Autowire(env: 'CDN_BASE_URL')] private string $cdnBaseUrl, ) {} public function supports(Request $request): bool { return true; } public function getScope(): string { return 'app'; } public function getConfig(): array { return [ 'apiBaseUrl' => $this->apiBaseUrl, 'cdnBaseUrl' => $this->cdnBaseUrl, ]; } }
No registration needed — any class implementing ConfigProviderInterface is auto-tagged.
Conditional providers
A provider that only runs on specific pages inspects the request:
final class MapConfigProvider implements ConfigProviderInterface { public function __construct( #[Autowire(env: 'MAP_API_KEY')] private string $mapApiKey, #[Autowire(env: 'MAP_ID')] private string $mapId, ) {} public function supports(Request $request): bool { return in_array($request->attributes->get('_route'), ['app_map_index', 'app_map_show'], true); } public function getScope(): string { return 'map'; } public function getConfig(): array { return [ 'mapApiKey' => $this->mapApiKey, 'mapId' => $this->mapId, ]; } }
The <script id="rc-map"> tag is injected only on the matched routes.
Configuration
# config/packages/env_to_js.yaml env_to_js: id_prefix: 'rc-' # default
The injected tag id is {id_prefix}{scope}. Pass the same value as the selector to createConfigReader().
Scope collision
If two active providers return the same scope, their configs are merged with array_merge. Last registered wins on key conflict.
Migration guides
From DefinePlugin / process.env
- Remove the
configureDefinePluginblock from your Webpack config (ordefinefrom your Vite config). - Group your formerly-injected variables into one or several
ConfigProviderInterfaceproviders. - Replace each
process.env.MY_VARin your source code withgetAppConfig('myVar')(the getter returned bycreateConfigReader).
Your webpack/vite artifact is now environment-agnostic — one build, promoted from staging to prod without a rebuild.
From window.* or data-options attributes
- Create
ConfigProviderInterfaceproviders for each group of variables currently assigned onwindowor indata-*attributes. - Replace
window.myVariableaccesses withgetAppConfig('myVariable')(the getter returned bycreateConfigReader). - Remove the inline
<script>ordata-*injection from your templates.
Requirements
- PHP >= 8.2
- Symfony >= 7.4
Development
make qa-vendor-install # install dependencies make qa # phpcs + phpstan + phpunit + rector make help # list all available commands
License
MIT
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 4
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-16