# Code Style and Conventions Standards for Cloudflare
This document outlines the code style and conventions standards for developers contributing to or maintaining code within the Cloudflare ecosystem. These standards aim to promote code readability, maintainability, consistency, performance, and security. They are designed to be used by developers and as context for AI coding assistants, ensuring a uniform and high-quality codebase.
## 1. General Principles
### 1.1. Readability
* **Do This:** Write code that is easy to understand at a glance. Use meaningful variable names, clear comments, and consistent formatting.
* **Don't Do This:** Write cryptic code that requires deep analysis to understand. Avoid overly clever tricks or shortcuts that sacrifice clarity.
* **Why:** Readability reduces the cognitive load on developers, making it easier to understand, debug, and modify the code. Higher readability also results in improved collaboration.
### 1.2. Maintainability
* **Do This:** Structure code into well-defined modules, functions, or classes with clear responsibilities. Use abstraction and encapsulation where appropriate. Make your code modular so individual components can be updated without massive ripple effects.
* **Don't Do This:** Create monolithic code blocks that are tightly coupled and difficult to change without introducing regressions.
* **Why:** Maintainable code is easier to evolve over time, adapt to changing requirements, and fix bugs. Reduces technical debt.
### 1.3. Consistency
* **Do This:** Follow these coding standards consistently across the entire project. Use automated linting and formatting tools to enforce the standards. Aim for consistent naming, indentation, and commenting styles.
* **Don't Do This:** Mix different coding styles within the same project. Allow inconsistencies to creep in over time, leading to a chaotic and confusing codebase.
* **Why:** Consistency reduces friction for developers moving between different parts of the codebase. Improves predictability and reduces errors.
### 1.4. Performance
* **Do This:** Write performant code that minimizes resource consumption and maximizes throughput by understanding Cloudflare Workers limitations. Use efficient algorithms and data structures. Optimize critical code paths. Leverage caching effectively, and understand considerations for cold starts. Understand which functionalities are offloaded to Cloudflare's edge efficiently vs origin server to reduce latency depending on workload.
* **Don't Do This:** Write inefficient code that wastes resources and slows down the application. Neglect performance considerations until late in the development cycle. Don't ignore Cloudflare's recommended caching strategies.
* **Why:** Cloudflare processes a massive amount of traffic. Performance is of the utmost importance for providing a fast and reliable service to customers.
### 1.5. Security
* **Do This:** Write secure code that protects against common vulnerabilities such as XSS, SQL injection, and CSRF. Follow security best practices, such as input validation, output encoding, and principle of least privilege. Be aware of Cloudflare-specific security measures.
* **Don't Do This:** Write code that is vulnerable to security attacks. Ignore security considerations until a vulnerability is discovered. Trust user input without validation.
* **Why:** Cloudflare sits at the edge of the network, making it a prime target for attackers. Security is paramount for protecting customer data and infrastructure.
## 2. Formatting
### 2.1. Indentation
* **Do This:** Use 4 spaces for indentation. Avoid tabs. Configure your editor to automatically convert tabs to spaces.
"""javascript
function myFunc(arg1, arg2) {
if (arg1 > arg2) {
return arg1;
} else {
return arg2;
}
}
"""
* **Don't Do This:** Mix tabs and spaces. Use inconsistent indentation levels.
### 2.2. Line Length
* **Do This:** Limit lines to a maximum of 120 characters. Break long lines into multiple shorter lines. Generally try to stay within 80 characters where possible, but be less strict if it impacts readability.
"""javascript
const myVeryLongVariableName = someFunction(
anotherArgument,
yetAnotherArgument,
andYetAnotherArgument
);
"""
* **Don't Do This:** Allow lines to become excessively long, making them difficult to read and edit.
### 2.3. Whitespace
* **Do This:** Use whitespace to improve readability. Add a space after commas, after colons, and around operators. Add blank lines to separate logical blocks of code.
"""javascript
const x = a + b;
const obj = { key1: value1, key2: value2 };
function anotherFunction() {
// ... code ...
}
"""
* **Don't Do This:** Use excessive or inconsistent whitespace, making the code look cluttered or sparse.
### 2.4. Braces
* **Do This:** Use braces for all code blocks, even single-line blocks. Place the opening brace on the same line as the statement, and the closing brace on its own line.
"""javascript
if (condition) {
doSomething();
} else {
doSomethingElse();
}
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
"""
* **Don't Do This:** Omit braces for single-line blocks. Use inconsistent brace styles.
## 3. Naming Conventions
### 3.1. General
* **Do This:** Use descriptive and meaningful names that clearly indicate the purpose of the variable, function, or class. Avoid abbreviations.
"""javascript
const numberOfRetries = 3;
function calculateTotalAmount(price, quantity) { /* ... */ }
class UserProfile { /* ... */ }
"""
* **Don't Do This:** Use single-letter variable names, cryptic abbreviations, or names that don't accurately reflect the purpose of the code element.
### 3.2. Variables
* **Do This:** Use "camelCase" for variable names. Use "const" by default, "let" when reassignment is needed, and avoid "var".
"""javascript
const firstName = "John";
let counter = 0;
"""
* **Don't Do This:** Use "snake_case" or "PascalCase" for variable names. Use "var" without a strong reason.
### 3.3. Functions
* **Do This:** Use "camelCase" for function names. Function names should typically be verbs or verb phrases.
"""javascript
function getUserName() { /* ... */ }
function processData(data) { /* ... */ }
"""
* **Don't Do This:** Use noun phrases for function names. Invent creative names that don't describe the function's purpose.
### 3.4. Classes
* **Do This:** Use "PascalCase" for class names.
"""javascript
class UserProfile { /* ... */ }
class AuthenticationService { /* ... */ }
"""
* **Don't Do This:** Use "camelCase" or "snake_case" for class names.
### 3.5. Constants
* **Do This:** Use "UPPER_SNAKE_CASE" for constant names.
"""javascript
const MAX_RETRIES = 5;
const API_ENDPOINT = "https://api.example.com";
"""
* **Don't Do This:** Use "camelCase" or "PascalCase" for constant names. Avoid the "var" keyword.
### 3.6. Cloudflare Worker Specifics
* **Do This**: When naming environment variables in Cloudflare Workers, prefix variables related to specific services or configurations with the service name (e.g., "KV_NAMESPACE", "AI_GATEWAY_API_KEY"). Use uppercase. Store secrets appropriately and avoid hardcoding.
* **Don't Do This**: Use generic environment variable names that might conflict (e.g., "API_KEY"). Hardcode important keys in the Worker code.
## 4. Comments
### 4.1. General
* **Do This:** Write clear and concise comments to explain complex logic, non-obvious behavior, or important design decisions. Keep comments up to date with the code.
"""javascript
// This function calculates the total amount by applying a discount
// based on the quantity purchased.
function calculateTotalAmount(price, quantity) {
// ... code ...
}
"""
* **Don't Do This:** Write redundant comments that simply repeat what the code already says. Write outdated comments that no longer accurately describe the code's behavior.
### 4.2. JSDoc
* **Do This:** Use JSDoc to document functions, classes, and modules, specifying parameters, return values, and any potential errors. This is especially important for public APIs and shared components.
"""javascript
/**
* Retrieves a user profile from the database.
* @param {string} userId - The ID of the user.
* @returns {Promise} A promise that resolves to the user profile.
* @throws {Error} If the user is not found.
*/
async function getUserProfile(userId) {
// ... code ...
}
"""
* **Don't Do This:** Omit JSDoc comments for important code elements. Provide incomplete or inaccurate JSDoc comments.
### 4.3. Commenting TODOs and FIXMEs
* **Do This**: Use "// TODO:" to mark code that needs future improvement. Use "// FIXME:" to mark code that is currently broken or has a known bug. Always include a description. For example, "// TODO: Refactor this function for better performance" or "// FIXME: This code causes a memory leak in some cases."
* **Don't Do This**: Leave vague "TODO" or "FIXME" comments without describing the problem.
## 5. Error Handling
### 5.1. General
* **Do This:** Use try-catch blocks to handle potential errors gracefully. Log errors appropriately. Provide meaningful error messages.
"""javascript
try {
const data = await fetchData();
processData(data);
} catch (error) {
console.error("Error fetching data:", error);
// Handle error gracefully, e.g., display an error message to the user
}
"""
* **Don't Do This:** Ignore errors or swallow exceptions without handling them. Provide generic error messages that don't help diagnose the problem.
### 5.2. Cloudflare Worker Specifics
* **Do This**: Use "waitUntil" to ensure asynchronous operations complete even after the Worker's response has been sent. Log errors using "console.error" for Cloudflare's logging system. Implement retry mechanisms for transient errors (e.g., network issues). Consider using Durable Objects for state management and error handling.
* **Don't Do This**: Rely on synchronous error handling alone, as it doesn't cover asynchronous operations within Workers. Fail to log errors, making debugging difficult without a reliable audit trail.
## 6. Specific Technologies
### 6.1. Cloudflare Workers
* **Do This:** Use modules and ES modules syntax to organize worker code. Leverage "async/await" for asynchronous operations. Use the "cf" object to access Cloudflare-specific request properties (e.g., "cf.country", "cf.colo"). Optimize for cold starts to minimize latency. Follow the [Cloudflare Workers documentation](https://developers.cloudflare.com/workers/) and best practices. Limit the use of third-party libraries in Workers to minimize bundle size and improve performance.
"""javascript
// Example Worker using modules and async/await
import { handleRequest } from './request-handler';
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
// request-handler.js
export async function handleRequest(request) {
const country = request.cf.country;
const url = new URL(request.url);
return new Response("Hello from ${country}! You requested: ${url.pathname}");
}
"""
* **Don't Do This:** Use global variables or mutable shared state. Block the event loop with synchronous operations. Ignore caching headers. Use large dependencies that increase worker size.
### 6.2. Cloudflare Pages
* **Do This:** Follow best practices for front-end development using JavaScript frameworks
danielsogl
Created Mar 6, 2025
This guide explains how to effectively use .clinerules
with Cline, the AI-powered coding assistant.
The .clinerules
file is a powerful configuration file that helps Cline understand your project's requirements, coding standards, and constraints. When placed in your project's root directory, it automatically guides Cline's behavior and ensures consistency across your codebase.
Place the .clinerules
file in your project's root directory. Cline automatically detects and follows these rules for all files within the project.
# Project Overview project: name: 'Your Project Name' description: 'Brief project description' stack: - technology: 'Framework/Language' version: 'X.Y.Z' - technology: 'Database' version: 'X.Y.Z'
# Code Standards standards: style: - 'Use consistent indentation (2 spaces)' - 'Follow language-specific naming conventions' documentation: - 'Include JSDoc comments for all functions' - 'Maintain up-to-date README files' testing: - 'Write unit tests for all new features' - 'Maintain minimum 80% code coverage'
# Security Guidelines security: authentication: - 'Implement proper token validation' - 'Use environment variables for secrets' dataProtection: - 'Sanitize all user inputs' - 'Implement proper error handling'
Be Specific
Maintain Organization
Regular Updates
# Common Patterns Example patterns: components: - pattern: 'Use functional components by default' - pattern: 'Implement error boundaries for component trees' stateManagement: - pattern: 'Use React Query for server state' - pattern: 'Implement proper loading states'
Commit the Rules
.clinerules
in version controlTeam Collaboration
Rules Not Being Applied
Conflicting Rules
Performance Considerations
# Basic .clinerules Example project: name: 'Web Application' type: 'Next.js Frontend' standards: - 'Use TypeScript for all new code' - 'Follow React best practices' - 'Implement proper error handling' testing: unit: - 'Jest for unit tests' - 'React Testing Library for components' e2e: - 'Cypress for end-to-end testing' documentation: required: - 'README.md in each major directory' - 'JSDoc comments for public APIs' - 'Changelog updates for all changes'
# Advanced .clinerules Example project: name: 'Enterprise Application' compliance: - 'GDPR requirements' - 'WCAG 2.1 AA accessibility' architecture: patterns: - 'Clean Architecture principles' - 'Domain-Driven Design concepts' security: requirements: - 'OAuth 2.0 authentication' - 'Rate limiting on all APIs' - 'Input validation with Zod'
# Testing Methodologies Standards for Cloudflare This document outlines the coding standards for testing methodologies within Cloudflare, focusing on unit, integration, and end-to-end testing, emphasizing the unique aspects of the Cloudflare ecosystem. Adhering to these standards ensures maintainability, performance, and security. ## 1. General Testing Principles ### 1.1 Test Pyramid Adherence **Standard:** Follow the test pyramid: many unit tests, fewer integration tests, and even fewer end-to-end tests. **Why:** Reduces feedback loops, minimizes flaky tests, and lowers maintenance overhead. **Do This:** Design tests to minimize reliance on external dependencies at the unit level. Favour focused integration tests over broad end-to-end tests when possible. **Don't Do This:** Create primarily end-to-end tests, leading to slow feedback and high maintenance costs. Neglect unit tests, resulting in harder-to-debug integration and end-to-end failures. ### 1.2 Test-Driven Development (TDD) **Standard:** Consider Test-Driven Development, especially for complex logic within Workers or Pages Functions. **Why:** Improves code design, reduces defects, and ensures comprehensive test coverage. **Do This:** Write a failing test *before* implementing the actual code. Refactor mercilessly after the test passes. **Don't Do This:** Write tests after the code is complete; this often leads to tests that merely confirm existing behavior instead of driving design. ### 1.3 Code Coverage **Standard:** Aim for high code coverage but prioritize meaningful tests over raw coverage numbers. **Why:** High coverage reduces the risk of uncaught bugs, but not all coverage is equal. **Do This:** Use code coverage tools to identify untested areas and focus on writing tests for critical business logic and edge cases. **Don't Do This:** Strive for 100% code coverage at the expense of test quality. Meaningless tests that don't assert meaningful behavior are harmful. ### 1.4 Test Environment Parity **Standard:** Ensure test environments closely match production environments, including Cloudflare configurations and dependencies. **Why:** Reduces the risk of bugs in production due to environment differences. **Do This:** Use environment variables and configuration management tools to mirror production settings in test environments. Leverage Cloudflare's "wrangler dev" for local testing that simulates the production environment. **Don't Do This:** Use significantly different data sets or configurations in test versus production. ## 2. Unit Testing ### 2.1 Focus on Isolation **Standard:** Unit tests should only test a single unit of code (function, method, class) in complete isolation. **Why:** Enables fast, reliable tests and makes it easier to pinpoint the source of bugs. **Do This:** Use mocking and stubbing to isolate the unit under test from its dependencies. **Don't Do This:** Allow unit tests to depend on external services, databases, or the file system. ### 2.2 Mocking and Stubbing **Standard:** Use mocking and stubbing libraries effectively to control dependencies. **Why:** Enables isolation and allows simulating different scenarios and edge cases. **Do This:** Utilize libraries like "jest" or "vitest" (with "jest-mock" or similar functionality) for mocking in Workers. When creating Typescript interfaces, leverage these to define the shape of mocked objects. **Don't Do This:** Over-mock; only mock dependencies that are truly external to the unit under test or that have side effects. Avoid mocking simple data transfer objects. **Example (Worker Unit Test with Mocking - Using Jest):** """typescript // src/my-worker.ts export async function handleRequest(request: Request, env: { MY_KV_NAMESPACE: KVNamespace }): Promise<Response> { const value = await env.MY_KV_NAMESPACE.get("my-key"); if (value) { return new Response("Value from KV: ${value}"); } else { return new Response("Value not found in KV", { status: 404 }); } } // test/my-worker.test.ts import { handleRequest } from '../src/my-worker'; describe('handleRequest', () => { it('should return value from KV if found', async () => { const mockKV = { get: jest.fn().mockResolvedValue('test-value'), }; const mockEnv = { MY_KV_NAMESPACE: mockKV, }; const request = new Request('http://example.com'); const response = await handleRequest(request, mockEnv as any); const text = await response.text(); expect(response.status).toBe(200); expect(text).toBe('Value from KV: test-value'); expect(mockKV.get).toHaveBeenCalledWith('my-key'); }); it('should return 404 if value not found in KV', async () => { const mockKV = { get: jest.fn().mockResolvedValue(null), // Simulate no value found }; const mockEnv = { MY_KV_NAMESPACE: mockKV, }; const request = new Request('http://example.com'); const response = await handleRequest(request, mockEnv as any); expect(response.status).toBe(404); expect(await response.text()).toBe('Value not found in KV'); }); }); """ ### 2.3 Assertion Clarity **Standard:** Write assertions that clearly express the expected behavior. **Why:** Makes tests easier to understand and debug. **Do This:** Use descriptive assertion messages that explain what is being asserted. Utilize specific assertion methods provided by your testing framework (e.g., "expect(x).toBeGreaterThan(y)" instead of just "expect(x > y).toBe(true)"). **Don't Do This:** Use generic assertions without clear messages. Write assertions that are difficult to interpret. ### 2.4 Data Providers **Standard:** Use data providers (parameterized tests) to test the same logic with different inputs. **Why:** Reduces code duplication and makes it easier to test various scenarios. **Do This:** Use features like "describe.each" in Jest to run the same test with different data sets. ## 3. Integration Testing ### 3.1 Focused Scope **Standard:** Integration tests should verify the interaction between two or more units or components. **Why:** Ensures that different parts of the system work together correctly. **Do This:** Test the interaction between your worker and a KV namespace, or between a Pages Function and a database. **Don't Do This:** Create broad integration tests that cover too many components at once; this makes it harder to isolate the source of failures. ### 3.2 Real Dependencies **Standard:** Strive to use real dependencies where appropriate in integration tests (e.g., real KV namespaces, real databases). **Why:** Increases confidence that the system will work correctly in production. **Do This:** Use dedicated test KV namespaces or databases that are separate from production. **Don't Do This:** Mock out all dependencies in integration tests; this defeats the purpose of testing the integration. ### 3.3 Environment Configuration **Standard:** Manage environment-specific configurations for integration tests. **Why:** Ensures that tests run correctly in different environments (e.g., development, staging, production). **Do This:** Use environment variables to configure test dependencies. **Don't Do This:** Hardcode environment-specific values in tests. **Example (Integration Test - Cloudflare Worker + KV Namespace):** This example assumes you have a Cloudflare account and a KV namespace set up. """typescript // test/my-worker.integration.test.ts import { handleRequest } from '../src/my-worker'; describe('handleRequest Integration', () => { // Before running the tests, set up the test environment beforeAll(async () => { // You might need to authenticate with Cloudflare, potentially via API token // This depends on how you manage your KV namespaces, and this section // requires environment variables you create in the testing environment. // For example: // const apiKey = process.env.CLOUDFLARE_API_KEY; // const accountId = process.env.CLOUDFLARE_ACCOUNT_ID; // const namespaceId = process.env.TEST_KV_NAMESPACE_ID; // You might use the Cloudflare API to clear the KV contents before each test. (Example only - replace with your actual implementation). // await clearKvNamespace(apiKey, accountId, namespaceId); }); it('should retrieve and return a value from a real KV namespace', async () => { // Arrange: Put a test key-value pair into the KV namespace. const testKey = 'integration-test-key'; const testValue = 'integration-test-value'; // Put the value DIRECTLY into the KV during the setup, using D1 calls, for example, or a direct KV API call. // e.g. await putKvValue(apiKey, accountId, process.env.TEST_KV_NAMESPACE_ID, testKey, testValue); // Note: Replace "putKvValue" with the actual function that persists to KV. const mockEnv = { MY_KV_NAMESPACE: { get: jest.fn(async (key) => { // Simulate KV.get, returning the set value if the requested key matches if (key === 'my-key') { // Retrieve value from REAL KV NAMESPACE here. DO NOT use mockResolvedValue. // Use a D1 connection call or a direct KV API call via process.env.TEST_KV_NAMESPACE_ID. // For this example, we only return the integration test value, but a fully implemented // approach would have a switch statement for multiple keys. return testValue; } return null; // Key not found }), put: jest.fn(), // mock put if needed }, } as any; const request = new Request('http://example.com'); // Act: Call the handler function const response = await handleRequest(request, mockEnv); const text = await response.text(); // Assert: Verify the response and that KV.get was called. expect(response.status).toBe(200); expect(text).toBe("Value from KV: ${testValue}"); expect(mockEnv.MY_KV_NAMESPACE.get).toHaveBeenCalledWith('my-key'); // Assert called with the expected key }); // After running the test, cleanup resources afterAll(async () => { // Clean up the KV namespace after each test. Remove the key that was added in the "beforeAll" step. // For example: // await deleteKvValue(apiKey, accountId, process.env.TEST_KV_NAMESPACE_ID, testKey); // Remove the mocked environment values after the test runs. jest.clearAllMocks(); // important for cleaning up MockKV get/put methods. }); }); """ ### 3.4 KV Namespace Setup and Teardown **Standard:** Ensure that KV namespaces are properly set up before integration tests and cleaned up afterward. **Why:** Prevents test pollution and ensures repeatable tests. **Do This:** Use Cloudflare API or D1 to set initial data in test KV namespaces and remove it after the test is complete. ## 4. End-to-End (E2E) Testing ### 4.1 Realistic Scenarios **Standard:** E2E tests should simulate real user scenarios as closely as possible. **Why:** Ensures that the entire system works correctly from the user's perspective. **Do This:** Test complete workflows, such as a user signing up, logging in, and performing a specific action. **Don't Do This:** Test trivial scenarios that are already covered by unit and integration tests. ### 4.2 Automated Browser Testing **Standard:** Use automated browser testing tools like Playwright or Cypress. **Why:** Simulates user interactions in a real browser environment. **Do This:** Write tests that interact with the UI, submit forms, click buttons, and verify results. **Don't Do This:** Manually test E2E scenarios; this is time-consuming and error-prone. ### 4.3 Test Data Management **Standard:** Carefully manage test data for E2E tests. **Why:** Ensures that tests are repeatable and don't interfere with each other. **Do This:** Use a dedicated test database or KV namespace for E2E tests. Seed the database with known data before each test run. Clean up the data after the tests are complete. **Don't Do This:** Use production data for E2E tests. ### 4.4 Cloudflare-Specific E2E Considerations **Standard:** When testing Cloudflare features (e.g., Workers, Pages, Load Balancing), ensure that your E2E tests validate their proper functioning. **Do This:** * **Workers:** Test that your Workers are correctly handling requests, transforming data, and interacting with other services. * **Pages:** Test that your Pages are being served correctly, that assets are being cached, and that dynamic functions are working as expected. * **Load Balancing:** Test that traffic is being distributed correctly across your origin servers and that failover is working properly. * **Cache:** Validate cache invalidation and purging strategies. Confirm that content is being cached and served from the cache as expected. **Example (Playwright E2E Test - Verifying a Cloudflare Pages Function):** This example assumes you have a Cloudflare Pages project deployed with a function that returns "Hello, World!". """typescript // test/e2e/pages.spec.ts import { test, expect } from '@playwright/test'; test('Cloudflare Pages function returns "Hello, World!"', async ({ page }) => { await page.goto('https://your-pages-project.pages.dev/api/hello'); // Replace with your Pages URL const responseText = await page.textContent('body'); expect(responseText).toBe('Hello, World!'); }); test('Test a redirect', async ({ page }) => { await page.goto("https://your-pages-project.pages.dev"); await expect(page).toHaveURL("https://your-pages-project.pages.dev/redirected-page"); }); """ ## 5. Performance Testing ### 5.1 Load Testing **Standard:** Perform load testing to ensure that your application can handle expected traffic volumes. **Why:** Identifies performance bottlenecks and ensures that your application remains responsive under load. **Do This:** Use tools like Apache JMeter or k6 to simulate concurrent users accessing your application. Monitor response times, error rates, and resource utilization. Use "wrangler dev" to simulate production scenarios locally. ### 5.2 Stress Testing **Standard:** Perform stress testing to determine the breaking point of your application. **Why:** Identifies the maximum load that your application can handle before it becomes unstable. **Do This:** Gradually increase the load on your application until it starts to fail. Monitor error rates, response times, and resource utilization. ### 5.3 Cloudflare-Specific Performance Testing **Standard:** Validate Cloudflare features' performance benefits (e.g., CDN caching, Argo Smart Routing). **Do This:** * **CDN Caching:** Test with and without CDN caching enabled to measure the performance impact. * **Argo Smart Routing:** Compare response times with and without Argo enabled to see the difference in routing efficiency. * **Workers:** Test Worker performance using tools like "wrangler tail" to analyze execution times and resource usage. * **Cache analytics:** Leverage Cloudflare's built-in analytics to analyze cache hit ratios and identify potential optimization opportunities. ### 5.4 WebPageTest Integration **Standard:** Incorporate WebPageTest into your performance testing workflow for detailed front-end performance analysis. **Why:** Offers comprehensive insights into page load times, render blocking resources, and other front-end performance metrics. **Do This:** Integrate WebPageTest into your CI/CD pipeline to automatically run performance tests on every build. ## 6. Security Testing ### 6.1 Static Analysis **Standard:** Use static analysis tools to identify potential security vulnerabilities in your code. **Why:** Catches common security issues early in the development cycle. **Do This:** Integrate static analysis tools into your CI/CD pipeline, such as ESLint with security plugins, or specialized security scanners if needed for the languages you use. ### 6.2 Dynamic Analysis **Standard:** Perform dynamic analysis (penetration testing) to identify vulnerabilities in your running application. **Why:** Uncovers vulnerabilities that are difficult to find with static analysis. **Do This:** Use tools like OWASP ZAP or Burp Suite to test your application for common web vulnerabilities. Engage a security professional or firm to perform a comprehensive penetration test on a regular basis. ### 6.3 Cloudflare Security Features **Standard:** Leverage Cloudflare's built-in security features and test their effectiveness. **Do This:** * **WAF (Web Application Firewall):** Test that the WAF is blocking malicious requests. You can simulate attacks to ensure the WAF rules are functioning as intended. * **Bot Management:** Verify that bot traffic is being detected and mitigated. * **DDoS Protection:** Simulate DDoS attacks to test the effectiveness of Cloudflare's DDoS protection. * **Access Rules:** Ensure that access rules are correctly restricting access to your resources. Test positive and negative cases. ### 6.4 Input Validation **Standard:** Validate all user inputs to prevent injection attacks. **Why:** Prevents attackers from injecting malicious code or data into your application. **Do This:** Use strong input validation techniques to ensure that user inputs conform to the expected format and data type. **Example (Worker Input Validation):** """typescript addEventListener('fetch', (event) => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request: Request): Promise<Response> { const { searchParams } = new URL(request.url); const name = searchParams.get('name'); if (!name || !/^[a-zA-Z]+$/.test(name)) { return new Response('Invalid name. Only letters are allowed.', { status: 400 }); } return new Response("Hello, ${name}!"); } """ ## 7. CI/CD Integration ### 7.1 Automated Testing **Standard:** Integrate all tests into your CI/CD pipeline. **Why:** Ensures that tests are run automatically on every code change. **Do This:** Configure your CI/CD system to run unit, integration, and E2E tests on every build. ### 7.2 Reporting **Standard:** Generate comprehensive test reports and dashboards. **Why:** Provides visibility into the quality of your code and helps identify trends. **Do This:** Use tools like Jest's built-in reporting features or third-party reporting services to generate test reports. Visualize test results using dashboards. ### 7.3 Rollback Strategy **Standard:** Implement a rollback strategy in case of test failures in production. **Why:** Minimizes the impact of bugs on users. **Do This:** Use feature flags, blue-green deployments, or canary releases to roll back changes quickly if tests fail in production. When using Cloudflare Pages, leverage preview deployments to examine changes prior to pushing to producton. By adhering to these testing methodologies standards, Cloudflare developers can build robust, reliable, and secure applications. This document should be considered a living document, reviewed and updated regularly to reflect the latest best practices and technologies.
# Deployment and DevOps Standards for Cloudflare This document outlines deployment and DevOps standards for developing applications and services on Cloudflare. Adhering to these standards ensures maintainability, performance, security, and efficient operation within the Cloudflare ecosystem. ## 1. Build Processes and CI/CD Pipelines ### 1.1 Standard: Automate Build and Deployment **Do This**: Implement CI/CD pipelines to automate build, test, and deployment processes. **Don't Do This**: Manually build and deploy code to Cloudflare environments. **Why**: Automation reduces human error, speeds up deployment, and enables faster iteration cycles. **Explanation**: Use platforms like GitLab CI/CD, GitHub Actions, or Jenkins to create automated pipelines triggered by code changes. Your pipeline should include stages for building, testing, and deploying your Cloudflare Workers, Pages functions, or other resources. **Code Example (GitHub Actions)**: """yaml name: Deploy to Cloudflare Workers on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Node.js uses: actions/setup-node@v3 with: node-version: 18 - name: Install Wrangler run: npm install -g wrangler - name: Configure Wrangler run: wrangler config --api-token ${{ secrets.CF_API_TOKEN }} - name: Deploy Worker run: wrangler deploy --env production env: CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }} CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }} """ **Anti-Pattern**: Manually uploading code through the Cloudflare dashboard. This is error-prone and doesn't scale. ### 1.2 Standard: Version Control Everything **Do This**: Store all code, configuration files, and infrastructure-as-code (IaC) definitions in version control (e.g., Git). **Don't Do This**: Track changes using manual file backups or shared drives. **Why**: Version control provides traceability, allows collaboration, and simplifies rollback in case of issues. **Explanation**: Use a Git repository to store your Cloudflare Worker code, Wrangler configuration files ("wrangler.toml"), Terraform configurations, and any other deployment-related assets. Tag releases for easy identification and rollback. **Anti-Pattern**: Storing environment variables directly in the code or configuration files. Use Cloudflare Secrets or an external secrets management solution. ### 1.3 Standard: Use Infrastructure as Code (IaC) **Do This**: Define your Cloudflare infrastructure (e.g., DNS records, Page Rules, Workers routes, Firewall configurations) using IaC tools like Terraform or Pulumi. **Don't Do This**: Manually configure infrastructure through the Cloudflare dashboard. **Why**: IaC enables reproducible deployments, provides a clear audit trail, and facilitates collaboration. **Explanation**: Choose an IaC tool that suits your team's expertise and start defining your Cloudflare resources as code. **Code Example (Terraform)**: """terraform terraform { required_providers { cloudflare = { source = "cloudflare/cloudflare" version = "~> 4.0" } } } provider "cloudflare" { api_token = var.cloudflare_api_token } resource "cloudflare_worker_script" "my_worker" { name = "my-worker-script" content = file("worker.js") } resource "cloudflare_worker_route" "my_worker_route" { zone_id = var.cloudflare_zone_id pattern = "example.com/api/*" script_name = cloudflare_worker_script.my_worker.name } variable "cloudflare_api_token" { type = string description = "Cloudflare API Token" sensitive = true } variable "cloudflare_zone_id" { type = string description = "Cloudflare Zone ID" } """ **Anti-Pattern**: Manually creating DNS records or Firewall rules through the dashboard. This makes it difficult to track changes and reproduce environments. ### 1.4 Standard: Environment Configuration **Do This**: Externalize configuration using environment variables (Cloudflare Secrets or similar) to manage different application environments (development, staging, production). **Don't Do This**: Hardcode configuration values in the application's code. **Why**: This enhances security, portability, and makes it easy to adapt the same code for varied deployments. It prevents accidental exposure of sensitive credentials. **Explanation**: Cloudflare Workers supports environment variables through Wrangler's secrets management or via the Cloudflare dashboard. Leverage these to store API keys, database credentials, and other sensitive information. **Code Example (Wrangler and Cloudflare Secrets)** 1. **Set a secret:** """bash wrangler secret put MY_API_KEY """ 2. **Access the secret in your Worker:** """javascript export default { async fetch(request, env, ctx) { const apiKey = env.MY_API_KEY; // ... your code using apiKey } }; """ 3. **"wrangler.toml" to specify environment:** """toml name = "my-worker" type = "javascript" account_id = "your_account_id" workers_dev = true route = "" # or your route [vars] ENVIRONMENT = "production" # Or "staging", "development" [env.staging] name = "my-worker-staging" # Separate worker name to avoid conflicts route = "staging.example.com/api/*" """ **Anti-Pattern**: Committing API keys or database passwords to the Git repository. This is a major security risk. ## 2. Production Considerations ### 2.1 Standard: Monitoring and Logging **Do This**: Implement comprehensive monitoring and logging to detect and diagnose issues in production. **Don't Do This**: Rely solely on manual inspection or limited logging. **Why**: Monitoring provides real-time insights into application performance and helps identify anomalies. Logging provides a detailed history of events for debugging and auditing. **Explanation**: * **Cloudflare Analytics**: Utilize Cloudflare's built-in analytics dashboard for high-level metrics related to traffic, performance, and security events. * **Dedicated Logging Solutions**: Integrate with dedicated logging solutions like Datadog, Splunk, or ELK stack for more granular analysis and alerting. * **Workers Trace Events**: Leverage Workers Trace Events to capture performance data and identify bottlenecks within your Workers. **Code Example (Sending Logs to a Third-Party Service within a Worker)**: """javascript async function sendLog(data) { const logEndpoint = 'https://your-log-service.com/api/logs'; await fetch(logEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }); } export default { async fetch(request, env, ctx) { const startTime = Date.now(); const response = await fetch(request); const endTime = Date.now(); const latency = endTime - startTime; const logData = { url: request.url, status: response.status, latency: latency, environment: env.ENVIRONMENT // Read from env variable. }; ctx.waitUntil(sendLog(logData)); // Send log asynchronously return response; }, }; """ **Anti-Pattern**: Not having proper logging infrastructure that helps in debugging production issues. ### 2.2 Standard: Error Handling and Alerting **Do This**: Implement robust error handling and alerting mechanisms to proactively identify and respond to errors. **Don't Do This**: Ignore errors or rely on manual monitoring to detect failures. **Why**: Error handling ensures graceful degradation and prevents application crashes. Alerting allows you to quickly respond to critical issues. **Explanation**: * **Error Tracking**: Use error tracking tools like Sentry or Bugsnag to capture and analyze errors in your Workers and client-side applications. * **Alerting**: Configure alerts based on error rates, latency, or other critical metrics. Send alerts to appropriate channels (e.g., Slack, PagerDuty). * **Graceful Degradation**: Design your application to degrade gracefully in case of failures. Implement retry mechanisms for transient errors. **Code Example (Error Handling in a Worker)**: """javascript export default { async fetch(request, env, ctx) { try { const response = await fetch('https://api.example.com/data'); if (!response.ok) { throw new Error("API Error: ${response.status}"); } const data = await response.json(); return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' }, }); } catch (error) { console.error('Error fetching data:', error); ctx.waitUntil(reportError(error, request, env)); // Send error to error tracking service asynchronously return new Response('Internal Server Error', { status: 500 }); } }, }; async function reportError(error, request, env) { // Implement your error reporting logic here (e.g., send to Sentry) // Using environment variables for Sentry DSN const sentryDsn = env.SENTRY_DSN; if (sentryDsn) { // Mock Sentry integration (replace with actual Sentry SDK) console.log("Sending error to Sentry (${sentryDsn}): ${error.message}"); // Simulate sending error to Sentry return Promise.resolve({ success: true, message: "Error reported to Sentry" }); } else { console.warn("Sentry DSN not configured. Skipping error reporting."); return Promise.resolve({ success: false, message: "Skipped reporting due to missing config" }); } } """ **Anti-Pattern**: Displaying generic error messages to users without logging the error details. ### 2.3 Standard: Rollback Strategy **Do This**: Implement a clear rollback strategy to quickly revert to a previous working state in case of a failed deployment. **Don't Do This**: Lack a rollback plan or rely on manual intervention for rollbacks. **Why**: Rollbacks minimize downtime and prevent prolonged outages. **Explanation**: * **Automated Rollbacks**: Integrate rollback functionality into your CI/CD pipelines. Use version control tags or deployment history to identify the previous working state. * **Feature Flags**: Use feature flags to gradually roll out new features and quickly disable them if issues arise. Cloudflare Workers provides libraries for feature flag management. * **Canary Deployments**: Deploy new versions to a small subset of users to monitor performance and detect errors before rolling out to the entire user base. **Code Example (Feature Flags with Cloudflare Workers)**: """javascript import { initialize, isEnabled } from '@cloudflare/feature-flags'; const flags = await initialize(env.FEATURE_FLAGS_JSON); export default { async fetch(request, env, ctx) { if (await isEnabled('new-feature', request, flags)) { // Execute new feature code return new Response('New Feature is Enabled!'); } else { // Execute existing code return new Response('Existing Feature is Active.'); } }, }; """ **"wrangler.toml"** """toml [vars] FEATURE_FLAGS_JSON = ''' { "new-feature": { "default": false, "rules": [ { "target": "country", "values": ["US"] } ] } } ''' """ **Anti-Pattern**: Deploying significant updates during peak traffic hours without a rollback plan. ### 2.4 Standard: Performance Optimization **Do This**: Optimize your application for performance to minimize latency and improve user experience. **Don't Do This**: Ignore performance considerations or rely solely on Cloudflare's default settings. **Why**: Performance optimization reduces costs, improves user engagement, and enhances SEO. **Explanation**: * **Caching**: Leverage Cloudflare's caching capabilities to cache static assets and dynamic content. Configure cache TTLs and cache keys appropriately. * **Image Optimization**: Use Cloudflare Image Resizing or similar solutions to optimize images for different devices and screen sizes. * **Code Splitting**: Split your JavaScript code into smaller chunks to improve initial load times. * **Workers Optimization**: Optimize your Worker code for performance. Use efficient algorithms and avoid unnecessary network requests. Profile your Workers to identify bottlenecks. **Code Example (Caching in a Worker)**: """javascript export default { async fetch(request, env, ctx) { const cache = caches.default; const url = new URL(request.url); const cacheKey = new Request(url.toString(), request); let response = await cache.match(cacheKey); if (response) { console.log('Cache hit'); return response; } console.log('Cache miss'); response = await fetch(request); // Cache the new response. // NOTE: Responses are immutable. To store as a cache entry, the app must // clone the response. response = response.clone(); cache.put(cacheKey, response); return response; }, }; """ **Anti-Pattern**: Serving unoptimized images or caching static assets with short TTLs. ### 2.5 Standard: Security Best Practices **Do This**: Implement security best practices to protect your application from attacks. **Don't Do This**: Ignore security vulnerabilities or rely solely on Cloudflare's default security features. **Why**: Security protects your data, prevents disruptions, and maintains user trust. **Explanation**: * **Web Application Firewall (WAF)**: Use Cloudflare's WAF to protect against common web attacks. Configure WAF rules appropriately. * **Rate Limiting**: Implement rate limiting to protect against abuse and denial-of-service attacks. * **Authentication and Authorization**: Use strong authentication and authorization mechanisms to protect sensitive data and resources. Consider using Cloudflare Access for zero-trust access control. * **Regular Security Audits**: Conduct regular security audits to identify and remediate vulnerabilities. **Code Example (Using Cloudflare Access in a Worker)**: """javascript export default { async fetch(request, env, ctx) { const cfAccessClientId = env.CF_ACCESS_CLIENT_ID; const cfAccessClientSecret = env.CF_ACCESS_CLIENT_SECRET; if (!request.headers.get("cf-access-jwt-assertion")) { return new Response("Unauthorized", { status: 401 }) } // Your application logic here. This code will only execute if the user is authenticated by Cloudflare Access. return new Response('Hello, authenticated user!'); }, }; """ **Anti-Pattern**: Leaving default credentials or exposing sensitive information in error messages. By adhering to these standards, development teams can ensure their applications and services deployed on Cloudflare are high-performing, secure, and easily maintainable. This document should be continuously updated to reflect new features and best practices within the Cloudflare ecosystem.
# Component Design Standards for Cloudflare This document outlines the component design standards for Cloudflare development. Adhering to these standards ensures reusable, maintainable, performant, and secure components across the platform. It is designed to guide developers and inform AI coding assistants. ## 1. Architectural Principles ### 1.1 Single Responsibility Principle (SRP) * **Standard:** Each component must have one, and only one, reason to change. * **Why:** SRP ensures that components are focused and avoids tight coupling. A change to one aspect of the system should not require modifications to unrelated components. * **Do This:** Design components with a clear and specific purpose. Refactor large components into smaller, more manageable units. * **Don't Do This:** Create "god classes" or components that handle multiple unrelated responsibilities. * **Example:** A component that is responsible for both fetching data and rendering a UI. Should be split into a data fetching component and a UI rendering component. """javascript // Anti-pattern: Component with multiple responsibilities class UserProfile { fetchUserData(userId) { /* ... fetches user data ... */ } renderProfile(userData) { /* ... renders UI ... */ } } // Correct: Separated responsibilities class UserDataFetcher { fetchUserData(userId) { /* ... fetches user data ... */ return userData; } } class UserProfileRenderer { renderProfile(userData) { /* ... renders UI ... */ } } """ ### 1.2 Open/Closed Principle (OCP) * **Standard:** Components should be open for extension but closed for modification. * **Why:** OCP promotes stability and reduces the risk of introducing bugs during enhancements. New functionality is added by extending existing components via inheritance or composition rather than altering the existing code. * **Do This:** Favor composition over inheritance wherever possible. Use interfaces and abstract classes to define extension points. * **Don't Do This:** Modify existing component code to add new features. * **Example:** Using higher-order components in React to add functionality without modifying the original component. """javascript // HOC example const withLoading = (WrappedComponent) => { return (props) => { const [isLoading, setIsLoading] = React.useState(true); React.useEffect(() => { // Simulate loading setTimeout(() => setIsLoading(false), 1000); }, []); if (isLoading) { return <div>Loading...</div>; } return <WrappedComponent {...props} />; }; }; const MyComponent = (props) => { return <div>{props.data}</div>; }; const MyComponentWithLoading = withLoading(MyComponent); // Usage: <MyComponentWithLoading data="My Data" /> """ ### 1.3 Liskov Substitution Principle (LSP) * **Standard:** Subtypes must be substitutable for their base types without altering the correctness of the program. * **Why:** LSP ensures that inheritance is used correctly. Subtypes should not break the behavior expected of their base types, preventing unexpected runtime errors. * **Do This:** Ensure that derived classes fulfill the contract of their base classes. Avoid throwing unexpected exceptions or violating pre/post-conditions in subtypes. * **Don't Do This:** Create subtypes that significantly deviate from the expected behavior of the base type. ### 1.4 Interface Segregation Principle (ISP) * **Standard:** Clients should not be forced to depend upon interfaces that they do not use. * **Why:** ISP promotes loose coupling by ensuring that clients only need to know about the methods they actually use, avoiding unnecessary dependencies. * **Do This:** Break down large interfaces into smaller, more specific ones. Use role interfaces to define specific contracts. * **Don't Do This:** Create large, monolithic interfaces that force clients to implement methods they don't need. ### 1.5 Dependency Inversion Principle (DIP) * **Standard:** High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions. * **Why:** DIP decouples high-level modules from low-level modules, making the system more flexible and maintainable. Changes to low-level modules should not affect high-level modules. * **DoThis:** Use dependency injection to provide dependencies to components. Depend on interfaces rather than concrete implementations. * **Don't Do This:** Hardcode dependencies within components. Directly depend on concrete classes. """typescript // Anti-pattern: High-level module depends on low-level module without abstraction class PaymentProcessor { private stripeGateway: StripeGateway; constructor() { this.stripeGateway = new StripeGateway(); // Hard dependency } processPayment(amount: number) { this.stripeGateway.charge(amount); } } class StripeGateway { charge(amount: number) { // Stripe specific logic console.log("Charging ${amount} via Stripe"); } } // Correct: Dependency Inversion interface PaymentGateway { charge(amount: number): void; } class StripeGateway implements PaymentGateway { charge(amount: number) { // Stripe specific logic console.log("Charging ${amount} via Stripe via abstract PaymentGateway"); } } class PaymentProcessor { private paymentGateway: PaymentGateway; constructor(paymentGateway: PaymentGateway) { this.paymentGateway = paymentGateway; // Dependency injected } processPayment(amount: number) { this.paymentGateway.charge(amount); } } const stripePaymentProcessor = new PaymentProcessor(new StripeGateway()); stripePaymentProcessor.processPayment(100); """ ## 2. Component Design Patterns ### 2.1 Atomic Design * **Standard:** Utilize the Atomic Design methodology. Components are structured starting with fundamental HTML elements and scaling up to complex templates. * **Why:** Atomic Design offers a system for building UIs in a scalable and maintainable way. * **Do This:** Classify components as atoms, molecules, organisms, templates, or pages. * **Don't Do This:** Create monolithic UI components that cannot be reused. *Example:* * *Atoms:* Buttons, Input fields, labels. * *Molecules:* Search bar (input + button), Form field (label + input) * *Organisms:* Header (logo + navigation), Footer. ### 2.2 Composition over Inheritance * **Standard:** Favor composition over inheritance. * **Why:** Composition provides greater flexibility and avoids the problems associated with tight coupling. * **Do This:** Compose complex behaviors by combining simpler components. Use higher-order components, render props, or hooks to share functionality. * **Don't Do This:** Create deep inheritance hierarchies that are difficult to maintain. """jsx // Composition Example (React) function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div> ); } function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); } """ ### 2.3 Container/Presentational Pattern * **Standard:** Separate container components (managing state and data) from presentational components (rendering UI). * **Why:** Clarifies component responsibilities. Allows easier maintenance and testing. * **Do This:** Create container components that fetch data and pass it as props to presentational components. Presentational components should be pure functions that depend solely on their props. * **Don't Do This:** Mix data fetching and UI rendering logic within a single component. """javascript // Container Component function UserProfileContainer() { const [userData, setUserData] = React.useState(null); React.useEffect(() => { // Fetch user data from API fetch('/api/user') .then(response => response.json()) .then(data => setUserData(data)); }, []); if (!userData) { return <div>Loading...</div>; } return <UserProfile userData={userData} />; } // Presentational Component function UserProfile({ userData }) { return ( <div> <h1>{userData.name}</h1> <p>{userData.email}</p> </div> ); } """ ### 2.4 Strategy Pattern * **Standard:** Encapsulate different algorithms or behaviors behind a common interface. * **Why:** Allows for flexibility in choosing algorithms at runtime. Simplifies adding or modifying behaviors. * **Do This:** Define an interface for common algorithms. Create concrete classes implementing that interface, each with a specific algorithm. * **Don't Do This:** Hardcode conditional logic for selecting algorithms within a single component. """typescript // Strategy interface interface DiscountStrategy { applyDiscount(price: number): number; } // Concrete strategies class PercentageDiscount implements DiscountStrategy { private percentage: number; constructor(percentage: number) { this.percentage = percentage; } applyDiscount(price: number): number { return price * (1 - this.percentage); } } class FixedAmountDiscount implements DiscountStrategy { private amount: number; constructor(amount: number) { this.amount = amount; } applyDiscount(price: number): number { return price - this.amount; } } // Context class ShoppingCart { private discountStrategy: DiscountStrategy; constructor(discountStrategy: DiscountStrategy) { this.discountStrategy = discountStrategy; } setDiscountStrategy(discountStrategy: DiscountStrategy) { this.discountStrategy = discountStrategy; } calculateTotalPrice(items: { price: number }[]): number { let totalPrice = items.reduce((sum, item) => sum + item.price, 0); return this.discountStrategy.applyDiscount(totalPrice); } } // Usage const cart = new ShoppingCart(new PercentageDiscount(0.1)); // 10% discount const totalPrice = cart.calculateTotalPrice([{ price: 100 }, { price: 50 }]); console.log(totalPrice); // Output: 135 cart.setDiscountStrategy(new FixedAmountDiscount(20)); // $20 discount const totalPriceWithFixedDiscount = cart.calculateTotalPrice([{ price: 100 }, { price: 50 }]); console.log(totalPriceWithFixedDiscount); // Output: 130 """ ## 3. Cloudflare-Specific Considerations ### 3.1 Cloudflare Workers * **Standard:** For Cloudflare Workers, design functions following the "microservice" architecture pattern. Minimize dependencies. Optimize for cold starts. * **Why:** Workers have resource constraints. Efficient code minimizes resource usage. * **Do This:** Use asynchronous operations to prevent blocking the event loop. Cache frequently accessed data. Minimize the use of large dependencies utilizing tree shaking. * **Don't Do This:** Perform synchronous operations. Load unnecessary dependencies. """javascript // Example: Cloudflare Worker with caching and async fetch addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { const cache = caches.default; let response = await cache.match(request); if (!response) { response = await fetch(request); // Only cache successful responses if (response.status === 200) { event.waitUntil(cache.put(request, response.clone())); } } return response; } """ ### 3.2 Cloudflare Pages * **Standard:** When using Cloudflare Pages, design components to use the latest framework recommended by Cloudflare, currently often React-based frameworks like Next.js or Remix. * **Why:** Cloudflare Pages is designed to work seamlessly with modern web frameworks. * **Do This:** Leverage server-side rendering (SSR) or static site generation (SSG) for improved performance and SEO. Utilize Cloudflare Functions for dynamic functionality. Apply best coding practices regarding Cloudflare KV for data persistence. * **Don't Do This:** Rely on client-side rendering (CSR) for critical content. Neglect to optimize images and other assets. ### 3.3 Cloudflare KV * **Standard:** Use Cloudflare KV for storing small to medium-sized data. Design your keys to be efficient for retrieval. * **Why:** KV provides a fast, globally distributed key-value store suitable for configuration and user data. * **Do This:** Design well-structured keys. Batch operations for efficiency. Use appropriate data serialization. * **Don't Do This:** Store large files in KV. Neglect to handle eventual consistency. Overwrite KV entries too frequently. """javascript // Example: Using Cloudflare KV in a Worker addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { const key = 'my-data'; let data = await MY_KV_NAMESPACE.get(key); if (!data) { data = JSON.stringify({ message: 'Hello from KV!' }); await MY_KV_NAMESPACE.put(key, data); } return new Response(data, { headers: { 'content-type': 'application/json' } }); } """ ## 4. Component Implementation Details ### 4.1 Naming Conventions * **Standard:** Use descriptive and consistent naming conventions. * **Why:** Improves code readability and maintainability. * **Do This:** Use PascalCase for component names (e.g., "UserProfile"). Use camelCase for function names (e.g., "fetchUserData"). Use SCREAMING_SNAKE_CASE for constants (e.g., "MAX_RETRIES"). * **Don't Do This:** Use ambiguous or overly abbreviated names. Use inconsistent naming schemes. ### 4.2 Error Handling * **Standard:** Implement robust error handling. * **Why:** Prevents unexpected crashes and provides informative error messages. * **Do This:** Use try-catch blocks to handle exceptions. Log errors appropriately using Cloudflare's logging functionalities. Provide user-friendly error messages or fallback UI. * **Don't Do This:** Ignore errors. Display stack traces to end-users. """javascript // Example: Error handling in a Cloudflare Worker async function handleRequest(request) { try { const data = await fetchData(); return new Response(JSON.stringify(data), { headers: { 'content-type': 'application/json' } }); } catch (error) { console.error('Error fetching data:', error); return new Response('Internal Server Error', { status: 500 }); } } """ ### 4.3 Testing * **Standard:** Write comprehensive unit and integration tests. * **Why:** Ensures component correctness and prevents regressions. * **Do This:** Use a testing framework like Jest or Mocha. Write tests for all critical functionality. Aim for high code coverage. Utilize mocking and stubbing to isolate components during testing. * **Don't Do This:** Neglect to write tests. Write superficial tests that don't verify behavior. ## 5. Performance Optimization ### 5.1 Code Splitting * **Standard:** Implement code splitting to reduce initial load time. * **Why:** Improves application performance by only loading necessary code. * **Do This:** Use dynamic imports to load components on demand. Leverage Webpack or Parcel for automatic code splitting. * **Don't Do This:** Load all code upfront, particularly large libraries when they might not be immediately needed. """javascript // Example: Dynamic import in React const MyComponent = React.lazy(() => import('./MyComponent')); <React.Suspense fallback={<div>Loading...</div>}> <MyComponent /> </React.Suspense> """ ### 5.2 Memoization * **Standard:** Use memoization to avoid unnecessary re-renders. * **Why:** Improves performance by caching the results of expensive calculations or rendering. * **Do This:** Use "React.memo" for functional components. Use "shouldComponentUpdate" or "PureComponent" for class components. * **Don't Do This:** Memoize components indiscriminately, as the memoization check might be more expensive than rerendering. ### 5.3 Image Optimization * **Standard:** Optimize images for web delivery. * **Why:** Reduces page load time and improves user experience. * **Do This:** Use optimized formats like WebP. Resize images appropriately. Use lazy loading. Leverage Cloudflare's image optimization features whenever possible. * **Don't Do This:** Serve large, uncompressed images. Neglect to use responsive images for different screen sizes. This comprehensive guide provides a solid foundation for building high-quality components within the Cloudflare ecosystem. Consistent application of these standards promotes maintainability, performance, and security -- leading to a robust and scalable platform.
# Tooling and Ecosystem Standards for Cloudflare This document outlines the coding standards related to tooling and ecosystem best practices for Cloudflare development. Following these guidelines ensures maintainable, performant, and secure code that integrates seamlessly with the Cloudflare ecosystem. These standards are designed to be used by developers and as context for AI coding assistants. ## 1. Development Environment and Tooling ### Standard 1.1: Use Recommended IDEs and Editors **Do This:** * Use VS Code (with extensions), IntelliJ IDEA (with plugins), or similar IDEs with robust support for JavaScript, TypeScript, and Go, depending on the project. * Configure your editor to use Prettier for automatic code formatting on save. * Install linters like ESLint (for JavaScript/TypeScript) and golangci-lint (for Go). * Utilize IDE features such as code completion, refactoring tools, and debugging support. **Don't Do This:** * Rely solely on simple text editors without code completion, linting, and formatting capabilities. * Ignore IDE warnings and suggestions, as they often highlight potential issues. **Why:** * IDEs provide advanced features that improve developer productivity, reduce errors, and ensure code consistency. * Consistent formatting and linting reduce cognitive load during code review, making it easier to identify issues. **Example (VS Code Configuration):** """json // .vscode/settings.json { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "eslint.validate": [ "javascript", "javascriptreact", "typescript", "typescriptreact" ], "files.eol": "\n", "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true } """ ### Standard 1.2: Leverage Package Managers **Do This:** * Use "npm" or "yarn" for JavaScript/TypeScript projects to manage dependencies. * Utilize "go modules" for Go projects to handle dependencies and versioning. * Specify version ranges in your "package.json" or "go.mod" files to allow for minor updates while preventing breaking changes. Use semantic versioning ("semver") ranges (e.g., ""^1.2.3""). * Regularly update dependencies to benefit from bug fixes, performance improvements, and security patches. **Don't Do This:** * Manually download and include library files in your project. * Use outdated package managers or dependency management systems. * Avoid using specific versions or version ranges for dependencies. **Why:** * Package managers automate the process of installing, updating, and managing dependencies, minimizing errors and ensuring consistency across environments. * Specifying version ranges allows for automatic updates within safe boundaries. **Example (package.json):** """json { "name": "cloudflare-worker-example", "version": "1.0.0", "devDependencies": { "@cloudflare/workers-types": "^4.0.0", "typescript": "^5.0.0", "wrangler": "^3.0.0", "prettier": "^3.0.0", "eslint": "^8.0.0" }, "dependencies": { "itty-router": "^4.0.8" }, "scripts": { "format": "prettier --write '**/*.{js,ts,json,md}'" } } """ ### Standard 1.3: Utilize Cloudflare Wrangler **Do This:** * Use Wrangler (version 3 or later) for developing, testing, and deploying Cloudflare Workers. * Configure "wrangler.toml" to define your Worker's settings, including name, type, routes, and secrets. (Version 3 uses "_routes.json" for routing which is being replaced by more functionality in "wragler.toml") * Use Wrangler's local development environment ("wrangler dev") to test your Worker locally before deploying it. * Use Wrangler's publishing commands ("wrangler publish") to deploy Workers to the Cloudflare global network. * Leverage Wrangler secrets to manage sensitive data, such as API keys. **Don't Do This:** * Deploy Workers directly without testing them locally. * Hardcode sensitive data (e.g., API keys, passwords) in your code. * Skip versioning Wrangler in your development environment. **Why:** * Wrangler simplifies the development, testing, and deployment workflow for Cloudflare Workers. * It provides a consistent and reliable way to manage your Workers and their dependencies. **Example (wrangler.toml):** """toml name = "my-worker" main = "src/index.ts" compatibility_date = "2024-01-01" # Latest release workers_dev = true [vars] MY_VARIABLE = "some-value" kv_namespaces = [ { binding = "MY_KV_NAMESPACE", id = "YOUR_KV_NAMESPACE_ID" } ] # Optional, but recommended for production [triggers] crons = ["0 0 * * *"] # Run daily at midnight UTC [durable_objects] bindings = [ {name = "MY_DURABLE_OBJECT", class_name = "MyDurableObject"} ] [r2_buckets] bindings = [ {name = "MY_R2_BUCKET", bucket_name = "my-bucket"} ] """ ### Standard 1.4: Test Automation **Do This:** * Implement unit tests to verify the functionality of individual modules and functions using testing frameworks like Jest or Mocha. * Write integration tests to ensure that different parts of your application work together correctly. * Use mocking and stubbing to isolate units of code during testing. * Automate tests as part of your build and deployment process. **Don't Do This:** * Skip writing tests, hoping that your code "just works." * Write tests that are too tightly coupled to the implementation details of your code. * Manually run tests on each code change. **Why:** * Automated testing improves code quality, reduces bugs, and makes it easier to refactor code. * It provides a safety net that allows you to make changes with confidence. **Example (Jest Unit Test):** """javascript // src/handler.test.js const { handleRequest } = require('./handler'); describe('handleRequest', () => { it('should return a 200 OK response', async () => { const request = new Request('https://example.com'); const response = await handleRequest(request); expect(response.status).toBe(200); }); it('should return a custom message', async () => { const request = new Request('https://example.com'); const response = await handleRequest(request); const body = await response.text(); expect(body).toContain('Hello worker!'); }); }); """ ### Standard 1.5: Use Infrastructure as Code (IaC) **Do This:** * Define your Cloudflare infrastructure (e.g., Workers, KV Namespaces, DNS records, Firewall rules) using Terraform or similar IaC tools. * Store your IaC configurations in version control alongside your application code. * Use CI/CD pipelines to automatically deploy infrastructure changes. **Don't Do This:** * Manually configure your Cloudflare infrastructure through the web UI. * Store infrastructure configurations in ad-hoc scripts or configuration files. **Why:** * IaC allows you to manage your infrastructure in a consistent, repeatable, and auditable way. * It enables you to automate infrastructure provisioning and deployment, reducing errors and improving efficiency. **Example (Terraform Configuration for Worker):** """terraform resource "cloudflare_worker_script" "example" { name = "my-worker" content = file("worker.js") plain_text_binding { name = "MY_VARIABLE" text = "some-value" } } resource "cloudflare_worker_route" "example" { zone_id = "YOUR_ZONE_ID" pattern = "example.com/*" script_name = cloudflare_worker_script.example.name } """ ## 2. Ecosystem Integration ### Standard 2.1: Leverage Cloudflare KV **Do This:** * Use Cloudflare KV for low-latency, globally distributed key-value storage for configuration, session data, or frequently accessed data. * Use batch operations to efficiently read and write multiple keys. * Set appropriate expiration times on keys to avoid stale data. * Consider using Durable Objects for use cases requiring strong consistency and statefulness. * Use "PUT" to create and update KV values, and "DELETE" to remove them. * Use "getWithMetadata" to retrieve metadata alongside the KV value. **Don't Do This:** * Use KV as a durable database for transactional data. * Store sensitive data (e.g., passwords, API keys) in KV without encryption. * Store large objects in KV (limit: a few MB per key). **Why:** * KV provides a fast and scalable storage solution for data that needs to be accessed quickly and globally. * KV is the only way for Cloudflare Workers to store persistant data without an origin DB. **Example (Worker with KV):** """typescript // src/index.ts export interface Env { MY_KV_NAMESPACE: KVNamespace; } export default { async fetch( request: Request, env: Env, ctx: ExecutionContext ): Promise<Response> { const url = new URL(request.url); const key = url.pathname.slice(1); if (request.method === 'PUT') { await env.MY_KV_NAMESPACE.put(key, await request.text(), {expirationTtl: 600}); return new Response("PUT ${key}"); } else if (request.method === 'GET') { const value = await env.MY_KV_NAMESPACE.get(key); return new Response(value); } else if (request.method === 'DELETE') { await env.MY_KV_NAMESPACE.delete(key); return new Response("DELETE ${key}"); } return new Response(null, { status: 405 }); }, }; """ ### Standard 2.2: Utilize Durable Objects **Do This:** * Consider Durable Objects for use cases requiring strong consistency, coordination, and statefulness, such as real-time collaboration, counters, or session management. * Design your Durable Objects to handle concurrent requests and state updates efficiently. Durable objects use an actor model * Lock critical sections of code to prevent race conditions. * Use Durable Objects for coordinating multiple workers. * Use "UNIQUE_KEY" to prevent collisions between Durable Objects. **Don't Do This:** * Use Durable Objects for simple read-only data storage. Use KV instead. * Store excessively large amounts of data in Durable Objects (consider using R2 for larger objects). * Make blocking calls within Durable Objects for extended periods. **Why:** * Durable Objects provide a robust and scalable platform for building stateful applications on Cloudflare Workers. * They offer strong consistency guarantees and low-latency access to state. **Example (Durable Object):** """typescript // src/durable-object.ts export class Counter { state: DurableObjectState; env: Env; constructor(state: DurableObjectState, env: Env) { this.state = state; this.env = env; this.state.blockConcurrencyWhile(async () => { this.count = (await this.state.storage.get("count")) || 0; }); } count:number; async fetch(request: Request) { let url = new URL(request.url); switch (url.pathname) { case "/increment": this.count++; await this.state.storage.put("count", this.count); break; case "/decrement": this.count--; await this.state.storage.put("count", this.count); break; case "/get": break; default: return new Response("Not found", {status: 404}); } return new Response(this.count.toString()); } } """ """toml #wrangler.toml [durable_objects] bindings = [ {name = "COUNTER", class_name = "Counter"} ] """ ### Standard 2.3: Utilize R2 Storage **Do This:** * Opt for Cloudflare R2 for storing large, infrequently accessed objects such as images, videos, and backups. * Use appropriately sized buckets for efficient storage management. Smaller buckets improve performance. * Employ R2's lifecycle policies to automatically manage object expiration and archiving. * Use multi-part uploads for uploading large objects in smaller chunks. **Don't Do This:** * Store frequently accessed data in R2 when low latency is essential (KV is more suitable). * Expose R2 buckets directly to the public without appropriate access controls. **Why:** * R2 provides a cost-effective storage solution for large amounts of data with global availability. * Low egress fees. **Example (Worker with R2):** """typescript // src/index.ts export interface Env { MY_R2_BUCKET: R2Bucket; } export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { const url = new URL(request.url); const key = url.pathname.slice(1); if (url.pathname === '/') { return new Response('Try GET /object-name') } if (request.method === 'PUT') { await env.MY_R2_BUCKET.put(key, request.body); return new Response("PUT ${key}"); } else if (request.method === 'GET') { const object = await env.MY_R2_BUCKET.get(key); if (object === null) { return new Response('Object Not Found', { status: 404 }); } return new Response(object.body); } else if (request.method === 'DELETE') { await env.MY_R2_BUCKET.delete(key); return new Response("DELETE ${key}"); } return new Response(null, { status: 405 }); }, }; """ ### Standard 2.4: Use Cloudflare Queues **Do This:** * Use Cloudflare Queues to decouple services and reliably process background tasks, such as sending emails, processing data, or triggering webhooks. * Implement retry mechanisms to handle message processing failures. * Monitor queue depth and processing latency to ensure that queues are operating efficiently. * Use batch processing to improve throughput when processing large numbers of messages. **Don't Do This:** * Use Queues for synchronous or real-time operations that require immediate responses. * Ignore message processing errors or failures. **Why:** * Queues provide a reliable and scalable platform for asynchronous task processing. * They decouple services, improving resilience and scalability. **Example (Worker using Queues):** """typescript // src/index.ts export interface Env { MY_QUEUE: Queue; } export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { const url = new URL(request.url); const message = url.searchParams.get("message"); if (message) { await env.MY_QUEUE.send(message); return new Response("Message sent to queue"); } return new Response("Message not found", { status: 400 }); }, async queue(batch: MessageBatch<string>, env: Env, ctx: QueueContext): Promise<void> { for (const message of batch.messages) { console.log("Received message: ${message.body}"); // Process the message here message.ack(); // Acknowledge the message } }, }; """ ## 3. Performance Optimization ### Standard 3.1: Optimize Worker Size **Do This:** * Minimize the size of your Worker scripts by removing unnecessary code, comments, and dependencies. * Use code minification and compression techniques to reduce the script size. * Use code splitting to break up large Worker scripts into smaller, more manageable modules. * Leverage esbuild or similar build tools, which can optimize worker bundle size. **Don't Do This:** * Include large, unused dependencies in your Worker scripts. * Deploy unminified or uncompressed Worker scripts. **Why:** * Smaller Worker scripts load faster, reducing latency and improving performance. * Smaller size limits the risk of hitting the max size limit. **Example (Using esbuild):** """javascript // esbuild.config.js const esbuild = require('esbuild'); esbuild.build({ entryPoints: ['src/index.ts'], bundle: true, minify: true, outfile: 'dist/worker.js', platform: 'browser', format: 'esm', }).catch(() => process.exit(1)); """ ### Standard 3.2: Cache Data Effectively **Do This:** * Cache frequently accessed data in Cloudflare's global CDN to reduce latency and improve response times. * Use appropriate cache TTLs (Time-To-Live) based on the data's volatility. * Use cache tags to invalidate specific objects in the cache when they are updated. * Leverage the Cache API within Workers for storing and retrieving cached data. * Configure Browser Cache TTL via Cache Rules to specify how long browsers should hold assets **Don't Do This:** * Cache sensitive data without proper encryption. Always use HTTPS. * Set overly long cache TTLs for dynamic data, leading to stale content. * Over-cache static content. * Under-cache dynamic content. **Why:** * Caching reduces the load on your origin server and improves the performance of your application for end users. **Example (Caching in Worker):** """typescript // src/index.ts async function handleRequest(request: Request): Promise<Response> { const cacheUrl = new URL(request.url); const cacheKey = new Request(cacheUrl.toString(), request); const cache = caches.default; let response = await cache.match(cacheKey); if (response) { console.log('Cache hit'); return response; } console.log('Cache miss'); // Get origin server response response = await fetch(request); response = new Response(response.body, response); response.headers.set('Cache-Control', 'max-age=600'); ctx.waitUntil(cache.put(cacheKey, response.clone())); return response; } """ ### Standard 3.3: Control Cloudflare features via API **Do This:** * Automate processes using the Cloudflare API * Protect your API key. * Rotate and Purge unused or temporary tokens/keys. * Leverage API capabilities instead of manually performing tasks in the dashboard. **Don't Do This:** * Leave unused API keys laying around. * Share or expose API keys. * Use the dashboard to perform tasks that can be performed by the API. **Why:** * Improved security * Version control * Automation * Better support **Example (Purge Cache via API):** """js //Purge Everything curl -X DELETE "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/purge_cache" \ -H "Content-Type: application/json" \ -H "X-Auth-Email: YOUR_EMAIL" \ -H "X-Auth-Key: YOUR_API_KEY" \ --data '{"purge_everything":true}' //Purge via Tag curl -X DELETE "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/purge_cache" \ -H "Content-Type: application/json" \ -H "X-Auth-Email: YOUR_EMAIL" \ -H "X-Auth-Key: YOUR_API_KEY" \ --data '{"tags":["tag1","tag2"]}' //Purge via File curl -X DELETE "https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/purge_cache" \ -H "Content-Type: application/json" \ -H "X-Auth-Email: YOUR_EMAIL" \ -H "X-Auth-Key: YOUR_API_KEY" \ --data '{"files":["http://example.com/example.jpg","http://example.com/example2.jpg"]}' """ Following these tooling and ecosystem standards will result in code that is secure, scalable, and seamlessly integrated with the Cloudflare platform. It provides a solid foundation for long-term maintainability and reduces the risk of encountering common pitfalls in Cloudflare development.
# Core Architecture Standards for Cloudflare This document outlines the core architectural standards for developing within the Cloudflare ecosystem. It is intended to provide a clear, consistent set of guidelines for developers building and maintaining Cloudflare Workers, Pages, and other Cloudflare-based solutions. Adhering to these standards will improve code maintainability, performance, security, and collaboration. These standards should be used by individual developers as well as used to customize AI development tools. ## 1. Fundamental Architectural Patterns ### 1.1. Event-Driven Architecture Cloudflare Workers are inherently event-driven. They react to incoming HTTP requests and other triggers. Prioritize designs that embrace this paradigm. **Do This:** * Design your Workers to be stateless and idempotent whenever possible. Each invocation should operate independently. * Use Cloudflare Queues for asynchronous processing of tasks triggered by events. * Leverage Cloudflare Durable Objects for managing persistent state when necessary. **Don't Do This:** * Create long-running processes within a Worker that block on I/O operations. * Rely on global mutable state within a Worker, as this can lead to unpredictable behavior due to the distributed nature of the platform. * Overuse Durable Objects for simple scenarios. Consider KV or R2 for simpler persistent storage needs. **Why:** Event-driven architecture promotes scalability, resilience, and responsiveness. Cloudflare's infrastructure is optimized for this pattern, enabling efficient resource utilization and minimal latency. **Code Example (Worker with Queue):** """javascript // src/worker.js addEventListener('fetch', event => { event.respondWith(handleRequest(event)); }); async function handleRequest(event) { const url = new URL(event.request.url); if (url.pathname === '/enqueue') { await MY_QUEUE.send({ message: "Task to be processed" }); return new Response("Task enqueued", { status: 202 }); } // ... other request handling logic return new Response("Hello worker!", { status: 200 }); } // src/queue-consumer.js export default { async queue(batch, env, ctx) { for (const message of batch.messages) { const data = message.body; console.log("Processing message:", data); // Perform asynchronous task await processTask(data); // Example task message.ack(); // Acknowledge successful processing } }, }; async function processTask(data) { // Implement your task processing logic here await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate work console.log("Task completed:", data); } """ **Anti-Pattern:** Synchronous, blocking operations. """javascript // Anti-pattern: blocking operation addEventListener('fetch', event => { // This will BLOCK the worker while waiting for the response from Google. const response = await fetch('https://www.google.com/'); event.respondWith(response); }); """ Instead, push slower operations of the request path to a Cloudflare Queue. ### 1.2. Microservices Architecture Consider breaking down complex applications into smaller, independent microservices deployed as separate Workers. **Do This:** * Define clear API boundaries between microservices. * Use Cloudflare's routing capabilities (e.g., Zones, Routes, Workers.dev subdomains) to direct traffic to the appropriate service. * Employ Cloudflare's Access product for authentication and authorization between microservices. **Don't Do This:** * Create tightly coupled microservices that depend on each other's internal state. * Expose internal microservice APIs directly to the public internet without proper authentication and authorization. * Implement complex orchestration logic within a single Worker; distribute it across multiple services. **Why:** Microservices promote modularity, independent deployments, and scalability. Cloudflare's infrastructure provides the tools necessary to manage and orchestrate a microservices architecture efficiently. **Code Example (Microservice Routing):** """javascript // src/worker-a.js (Microservice A) addEventListener('fetch', event => { event.respondWith(new Response("Microservice A", { status: 200 })); }); // src/worker-b.js (Microservice B) addEventListener('fetch', event => { event.respondWith(new Response("Microservice B", { status: 200 })); }); """ Configure Cloudflare Routes: * "example.com/api/a/*" -> "worker-a.example.workers.dev" * "example.com/api/b/*" -> "worker-b.example.workers.dev" **Anti-Pattern:** Monolithic worker architectures with many responsibilities. ### 1.3. Edge Computing Principles Leverage Cloudflare's global network to move computation closer to your users. **Do This:** * Cache frequently accessed static assets and API responses using Cloudflare's CDN. * Perform data transformations and manipulations within Workers at the edge to reduce latency. * Use GeoIP-based routing and personalization to deliver customized experiences based on user location. **Don't Do This:** * Force users to retrieve data from distant origins when it can be cached or computed at the edge. * Implement complex business logic that requires frequent access to centralized databases if it can be performed offline or at in the edge. * Store sensitive data in edge caches without proper encryption and access controls. **Why:** Edge computing reduces latency, improves performance, and enhances the user experience. Cloudflare's global network provides a powerful platform for deploying and running edge-based applications. **Code Example (Caching using Cache API):** """javascript addEventListener('fetch', event => { event.respondWith(handleRequest(event)); }); async function handleRequest(event) { const cache = caches.default; const url = event.request.url; let response = await cache.match(url); if (response) { console.log('Serving from cache'); return response; } console.log('Fetching from origin'); response = await fetch(event.request); // Cache the response for future requests. Consider caching API responses too! event.waitUntil(cache.put(url, response.clone())); return response; } """ **Anti-Pattern:** Unnecessary trips to origin servers, especially when caching would be effective. ## 2. Project Structure and Organization ### 2.1. Modular Codebase Break down your code into modular components with well-defined responsibilities. **Do This:** * Organize your code into separate files and directories based on functionality. * Use ES modules to import and export functions and classes between modules. * Create reusable components that can be shared across multiple Workers or projects. **Don't Do This:** * Write large, monolithic files that are difficult to understand and maintain. * Duplicate code across multiple files; create reusable functions instead. * Mix unrelated concerns within a single module. **Why:** Modular code is easier to understand, test, and maintain. It also promotes code reuse and reduces the risk of introducing bugs. **Code Example (Modular Codebase):** """ my-worker/ │ ├── src/ │ ├── handlers/ │ │ ├── user-handler.js │ │ └── product-handler.js │ ├── utils/ │ │ └── api-client.js │ ├── index.js (Worker entrypoint) │ ├── package.json └── wrangler.toml """ """javascript // src/handlers/user-handler.js export async function handleGetUser(request) { // ... logic to get a user return new Response(JSON.stringify({ user: "example" }), { headers: { 'Content-Type': 'application/json' } }); } """ """javascript // src/index.js import { handleGetUser } from './handlers/user-handler'; addEventListener('fetch', event => { const url = new URL(event.request.url); if (url.pathname === '/user') { event.respondWith(handleGetUser(event.request)); } else { event.respondWith(new Response("Hello!")); } }); """ **Anti-Pattern:** Putting all code into "index.js" ### 2.2. Configuration Management Externalize configuration settings from your code. **Do This:** * Use Cloudflare Workers environment variables for sensitive configuration settings like API keys and database credentials. * Store non-sensitive configuration settings in "wrangler.toml" or a separate configuration file. * Use different configuration settings for different environments (e.g., development, staging, production). **Don't Do This:** * Hardcode configuration settings directly into your code. * Commit sensitive configuration settings to your version control repository. * Use the same configuration settings for all environments (e.g., using production keys for development). **Why:** Externalizing configuration settings makes your code more portable, secure, and easier to manage across different environments. **Code Example (Environment Variables):** """javascript // wrangler.toml [vars] API_KEY = "your-api-key" // src/index.js addEventListener('fetch', event => { const apiKey = API_KEY; // Access through global scope console.log("API Key:", apiKey); // ... use the apiKey event.respondWith(new Response("Hello", { status: 200 })); }); """ **Anti-Pattern:** Hard-coding API keys into source code. ### 2.3. Logging and Monitoring Implement comprehensive logging and monitoring to track the performance and health of your Workers. **Do This:** * Use "console.log" for basic logging during development and debugging. * Integrate with a logging service (e.g., Sentry, Honeycomb) for production environments. * Use Cloudflare Analytics to monitor the performance and usage of your Workers. * Implement health checks to automatically detect and recover from failures. **Don't Do This:** * Log sensitive data (e.g., passwords, API keys) to the console or logging service. * Rely solely on "console.log" in production environments use logging services. * Ignore error messages or warnings in your logs. **Why:** Proper logging and monitoring are essential for identifying and resolving issues in production environments. They also provide valuable insights into the performance and usage of your Workers. **Code Example (Logging with a 3rd Party):** """javascript // Install sentry: npm install @sentry/browser @sentry/integrations import * as Sentry from "@sentry/browser"; import { Integrations } from "@sentry/integrations"; Sentry.init({ dsn: "YOUR_SENTRY_DSN", // Replace with your Sentry DSN integrations: [ new Integrations.GlobalHandlers({ onerror: true, onunhandledrejection: true, }), ], tracesSampleRate: 1.0, }); addEventListener('fetch', event => { try { event.respondWith(handleRequest(event)); } catch (e) { Sentry.captureException(e); event.respondWith(new Response("Internal Server Error", { status: 500 })); } }); async function handleRequest(event) { try { // ... your worker logic throw new Error("Example Error"); return new Response("Success", { status: 200 }); } catch (e) { Sentry.captureException(e); // Report exceptions to Sentry throw e; // Re-throw exception for handling } } """ **Anti-Pattern:** Not implementing any logging at all. ## 3. Specific Code Implementation ### 3.1. Error Handling Implement robust error handling to prevent unexpected crashes and provide informative feedback to users. **Do This:** * Use "try...catch" blocks to handle potential exceptions. * Return informative error messages to the client. * Implement retry mechanisms for transient errors. **Don't Do This:** * Ignore exceptions or swallow errors without logging them. * Expose sensitive error details to the client. * Rely on global error handlers to catch all exceptions. **Why:** Robust error handling improves the reliability and user experience of your applications. It also makes it easier to debug and resolve issues. **Code Example (Error Handling):** """javascript addEventListener('fetch', event => { event.respondWith(handleRequest(event)); }); async function handleRequest(event) { try { const response = await fetch('https://example.com/api'); if (!response.ok) { throw new Error("HTTP error! status: ${response.status}"); } const data = await response.json(); return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } }); } catch (error) { console.error("Fetch error:", error); return new Response(JSON.stringify({ error: "Failed to fetch data" }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } } """ **Anti-Pattern:** Not catching exceptions or logging errors. ### 3.2. Asynchronous Programming Effectively use asynchronous programming techniques to avoid blocking the main thread. **Do This:** * Use "async/await" syntax to write asynchronous code that is easy to read and understand. * Use "Promise.all" to execute multiple asynchronous operations in parallel. * Avoid blocking the main thread with long-running synchronous operations. **Don't Do This:** * Use callbacks instead of "async/await" unless you have a very specific reason. * Nest asynchronous operations excessively, leading to "callback hell". * Perform CPU-intensive operations in the main thread, blocking other requests. **Why:** Asynchronous programming is essential for building responsive and scalable applications. It allows you to perform I/O operations and other tasks without blocking the main thread. **Code Example (Asynchronous Programming):** """javascript async function fetchUserData(userId) { const response = await fetch("https://example.com/api/users/${userId}"); const data = await response.json(); return data; } async function fetchProductData(productId) { const response = await fetch("https://example.com/api/products/${productId}"); const data = await response.json(); return data; } addEventListener('fetch', event => { event.respondWith(handleRequest(event)); }); async function handleRequest(event) { try { const userDataPromise = fetchUserData(123); const productDataPromise = fetchProductData(456); // Execute both fetches in parallel const [userData, productData] = await Promise.all([userDataPromise, productDataPromise]); const combinedData = { user: userData, product: productData }; return new Response(JSON.stringify(combinedData), { headers: { 'Content-Type': 'application/json' } }); } catch (error) { console.error("Error fetching data:", error); return new Response(JSON.stringify({ error: "Failed to fetch data" }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } } """ **Anti-Pattern:** Sequential awaiting of multiple "fetch" calls when they could execute in parallel. ### 3.3. Security Best Practices Implement security best practices to protect your Workers from common security vulnerabilities. **Do This:** * Validate all user input to prevent injection attacks. * Use parameterized queries to prevent SQL injection. * Implement proper authentication and authorization mechanisms. * Encrypt sensitive data at rest and in transit. * Regularly update your dependencies to patch security vulnerabilities. * Use Cloudflare's Web Application Firewall (WAF) to protect your Workers from common web attacks. **Don't Do This:** * Trust user input without validation. * Store sensitive data in plain text. * Use weak or default passwords. * Expose sensitive information in error messages. * Disable security features without a valid reason. **Why:** Security is paramount. Failing to implement security best practices can expose your Workers and your users to significant risks. **Code Example (Input Validation):** """javascript addEventListener('fetch', event => { event.respondWith(handleRequest(event)); }); async function handleRequest(event) { const url = new URL(event.request.url); const username = url.searchParams.get('username'); if (!username || !/^[a-zA-Z0-9]+$/.test(username)) { return new Response(JSON.stringify({ error: "Invalid username" }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } // ... use the validated username return new Response("Hello, ${username}!", { status: 200 }); } """ **Anti-Pattern:** Directly using URL GET parameters without inspecting them. ### 3.4. Cloudflare specific configurations Ensure correct usage of Cloudflare ecosystem components. **Do This:** * Use KV Namespaces to store key-value data with global, low-latency access (when appropriate). * Use Durable Objects when strong consistency and coordination across multiple requests are necessary. * Use R2 for storing large binary objects such as images and videos offering S3-compatible API * Understand the billing implications of each Cloudflare service and optimize accordingly. **Don't Do This:** * Misusing KV for data that requires strong consistency. * Overusing Durable Objects for simple storage needs, incurring unnecessary costs and complexity. * Assuming unlimited resource availability. Be mindful of Cloudflare's usage limits. * Bypass Cloudflare CDN for static assets. **Why:** Utilizing the correct tools for their intended purpose ensures optimal performance, cost efficiency, and scalability within the Cloudflare environment. **Code Example (R2 Usage):** """javascript addEventListener('fetch', async event => { const url = new URL(event.request.url); if (url.pathname === '/upload') { event.respondWith(handleUpload(event)); } else if (url.pathname === '/download') { event.respondWith(handleDownload(event)); } else { event.respondWith(new Response("Hello!")); } }); async function handleUpload(event) { const body = await event.request.formData(); const file = body.get('file'); if (!file) { return new Response('No file uploaded', { status: 400 }); } await MY_BUCKET.put(file.name, await file.arrayBuffer()); //MY_BUCKET is bound via wrangler.toml return new Response('File uploaded successfully'); } async function handleDownload(event) { const objectName = 'your-object-name'; const object = await MY_BUCKET.get(objectName); if (!object) { return new Response('Object not found', { status: 404 }); } const headers = new Headers(); object.writeHttpMetadata(headers); headers.set('etag', object.httpEtag); return new Response(object.body, { headers, }); } """ ## 4. Testing ### 4.1 Unit Tests Write unit tests for individual components of a Cloudflare Worker in isolation. **Do This:** * Use testing frameworks such Jest or Mocha. * Mock external dependencies ("fetch", Cloudflare KV, Durable Objects) to ensure tests are isolated and deterministic. * Test edge cases and error scenarios. * Use CI/CD such as Gitlab CI/CD, Github Actions, Jenkins, etc. **Don't Do This:** * Write tests that rely on external resources or services without mocking. * Skip testing error handling logic. **Why:** Unit tests enable rapid development and confident refactoring by verifying the correctness of code components in isolation. **Example Unit Test (Jest):** """javascript //Example handler for user handling export async function handleGetUser(request) { // ... logic to get a user return new Response(JSON.stringify({ user: "example" }), { headers: { 'Content-Type': 'application/json' } }); } //handler.test.js using Jest import { handleGetUser } from './handler'; describe('handleGetUser', () => { it('should return a user object', async () => { const mockRequest = new Request('http://example.com/user'); // Mock request object const response = await handleGetUser(mockRequest); const data = await response.json(); expect(response.status).toBe(200); expect(data.user).toBe("example"); }); }); """ ### 4.2 Integration tests Write integration tests for Cloudflare Workers testing the integration across different components or services. **Do This:** * Test the interaction with cloudflare services such as KV namespaces, R2 Buckets or Durable Objects. * Use a staging or development environment to run the tests avoiding modifying production data. * Automate integration tests as part of a CI/CD pipeline. **Don't Do This:** * Run integration tests against production environments. * Skip testing interaction with critical services. **Why:** Integration tests ensure that different components/services work correctly together and interactions with third party services work as expected. ## 5. Documentation ### 5.1 In-code documentation Write documentation for functions, classes and modules. **Do This:** * Use JSDoc or similar standards for inline documentation for functions, classes, and modules. * Describe input parameters, expected outputs, and any potential side effects * Keep documentation up-to-date with code changes. **Don't Do This:** * Leave code undocumented, especially complex or critical sections. * Allow documentation to become outdated or inconsistent with the code. **Why:** Clear documentation ensures that code is easily understood, reducing burden on other developers. ### 5.2 API Documentation Write API documentation if the Cloudflare Worker acts as an API provider. **Do This:** * Specify endpoints, request payloads, response schemas, and authentication methods. * Follow OpenAPI specification for the API definition. * Use tools such as Swagger UI for interactive API exploration. **Don't Do This:** * Skip API documentation. Leave them poorly documented with no overview of its function. **Why:** Clear API documentation is essential to allow other developers and services to consume the api without external assistance. By adhering to these standards, you can ensure that your Cloudflare Workers are well-architected, performant, secure, and maintainable. This document should evolve and should be updated as new features and best practices emerge. This document serves as a guide to developers as well as used to customize AI code authoring tools.