Astro, renowned for its developer-friendly experience and focus on performance, has recently released version 4.10. This update brings two game-changing features that will revolutionize your development workflow and expand the possibilities with Astro:
Distinguishing client-side and server-side variables: This often resulted in convoluted configurations and unclear separation of concerns.Protecting sensitive credentials: Ensuring secrets remained secure in all environments and were not exposed to clients proved to be a major hurdle.Preventing secrets from being embedded in final build files: This security vulnerability could lead to unintended data exposure.
Type Safety: Enforces proper variable types, reducing errors and improving code quality.Client/Server Separation: Clearly distinguishes between variables accessible on the client and server, ensuring secure and appropriate data handling.Secret Protection: Protects sensitive information by classifying variables as "secret" and limiting their access to the server-side only.
Create a new Astro project: npm create astro@latest myapp cd myapp
Update your Astro configuration file: // astro.config.mjs import { defineConfig, envField } from "astro/config"; export default defineConfig({ experimental: { env: { schema: { API_URI: envField.string({ context: "server", access: "secret", default: "https://fakestoreapi.com/products", }), USER_NAME: envField.string({ context: "client", access: "public", default: "Melvin", }), }, }, }, });
In this example, we create two variables: API_URI (server-side, secret) and USER_NAME (client-side, public). Access variables within your Astro components: <!-- src/pages/index.astro --> --- import { USER_NAME } from 'astro:env/client'; import {API_URI } from 'astro:env/server'; await fetch(`${API_URI}`).then(res=>res.json()).then(json=>console.log(json)) --- <html> <body> <h1>{USER_NAME}</h1> </body> </html> <style> h1 { color: orange; } </style>
This code demonstrates how to access variables based on their context (client or server) and their intended use.
System environment variables .env file in the project root Environment-specific .env files (e.g., .env.development, .env.production)
// astro.config.mjs
import { defineConfig, envField } from 'astro/config';
export default defineConfig({
experimental: {
env: {
schema: {
API_URL: envField.string({
default: 'http://localhost:3000/api', // Development default
context: 'server',
}),
NODE_ENV: envField.string({
default: 'development',
context: 'client',
}),
},
},
},
});
API_URL=https://our-production-api.com
Environment-specific variables: CI/CD pipelines can set variables for different stages (e.g., CI=true, DEPLOYMENT_ENV=production).Secure access to sensitive information: Sensitive information can be securely stored and accessed within Astro.Environment-specific build artifacts: Different build artifacts can be generated based on environment variables.
Compilation: Use astro build to compile Astro components into standalone bundles.Integration: Import and use these bundles within your non-Astro project, with Astro handling client-side hydration.
Set up a new project: npm init -y npm install astro express ejs npm install -D nodemon
Create an Astro component: <!-- src/components/MyComponent.astro --> --- --- <h1>Hello from Astro component</h1>
Export the component: // src/all.js export { default as MyComponent } from "./components/MyComponent.astro";
Create a custom Astro adapter: // adapter/index.mjs export default function () { return { name: "myadapter", hooks: { "astro:config:done": ({ setAdapter }) => { setAdapter({ name: "myadapter", serverEntrypoint: new URL("./server-entrypoint.mjs", import.meta.url) .pathname, supportedAstroFeatures: { serverOutput: "stable", }, exports: ["manifest"], }); }, "astro:build:setup": ({ vite, target }) => { if (target === "server") { vite.build.rollupOptions.input.push("src/all.js"); } }, }, }; }
The adapter configures the build process and specifies the server entry point. Define the server entry point: // adapter/server-entrypoint.mjs export function createExports(manifest) { return { manifest }; }
This function is responsible for generating the build output. Configure Astro for server-side rendering: // astro.config.mjs import { defineConfig } from "astro/config"; import adapter from "./adapter/index.mjs"; export default defineConfig({ output: "server", adapter: adapter(), integrations: [], });
Build the project: npm run build
Set up the Express server: // server.mjs import * as components from "./dist/server/all.mjs"; import { renderers } from "./dist/server/renderers.mjs"; import { manifest } from "./dist/server/entry.mjs"; import { experimental_AstroContainer as AstroContainer } from "astro/container"; import express from "express"; import { fileURLToPath } from "url"; import path, { dirname } from "path"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const container = await AstroContainer.create({ manifest, renderers, resolve(s) { const found = manifest.entryModules[s]; if (found) { return `/dist/client/${found}`; } return found; }, }); const app = express(); app.set("view engine", "ejs"); app.set("views", path.join(__dirname, "views")); const port = 5000; app.get("/", async (req, res) => { const html = await container.renderToString(components.MyComponent); res.render("index", { body: html, title: "Welcome to Astro-in-Express" }); }); app.listen(port, () => { console.log(`Server listening on port ${port}`); });
Create an EJS template: <!-- views/index.ejs --> <!DOCTYPE html> <html> <head> <title><%= title %></title> </head> <body class=""> <%- body %> </body> </html>
Start the server: npm run serve
Access http://localhost:5000/ to see your Astro component rendered in the Express environment.
Wider cross-framework compatibility: The Container API could pave the way for seamless integration between even more diverse web technologies.Streamlined developer workflows: New tools and practices could emerge to simplify the development process for complex, multi-framework applications.Influence on industry standards: astro:env could inspire other frameworks to adopt similar approaches to managing environment variables.
0 comments:
Post a Comment