You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pulumi(TypeScript、AWS):如何上传含嵌套目录文件的多文件至S3以实现静态网站托管

Solution to Upload Nested Nuxt.js dist Files to S3 with Pulumi/TypeScript

Got it, I’ve faced this exact scenario with Nuxt.js projects and Pulumi before—your original code only handles top-level files in the dist directory, but we can fix that with a recursive file traversal approach. Here's a complete TypeScript solution that uploads every nested file while preserving your directory structure:

Step 1: Full Working Code

First, make sure you have the required dependencies installed (@pulumi/aws, @pulumi/pulumi, mime, and Node.js's built-in fs/path modules—no extra packages needed beyond what you likely already have):

import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
import * as mime from "mime";
import * as fs from "fs";
import * as path from "path";

// Create an S3 bucket optimized for Nuxt static/SPA hosting
const siteBucket = new aws.s3.Bucket("nuxt-static-site-bucket", {
    website: {
        indexDocument: { suffix: "index.html" },
        errorDocument: { key: "200.html" }, // Critical for Nuxt SPA routing fallback
    },
});

// Recursive helper to fetch all files in a directory (including subdirectories)
function getAllFiles(directory: string): string[] {
    const entries = fs.readdirSync(directory, { withFileTypes: true });
    
    // Collect all files in the current directory
    const files = entries
        .filter(entry => entry.isFile())
        .map(entry => path.join(directory, entry.name));
    
    // Recursively process subdirectories and add their files
    const subdirectories = entries.filter(entry => entry.isDirectory());
    for (const dir of subdirectories) {
        files.push(...getAllFiles(path.join(directory, dir.name)));
    }
    
    return files;
}

const distDir = "dist"; // Path to your Nuxt build output
const allDistFiles = getAllFiles(distDir);

// Upload each file to S3, preserving directory structure
allDistFiles.forEach(filePath => {
    // Use the relative path from dist as the S3 object key (e.g., "_nuxt/fonts/element-icons.ttf")
    const s3ObjectKey = path.relative(distDir, filePath);
    
    new aws.s3.BucketObject(s3ObjectKey, {
        bucket: siteBucket,
        source: new pulumi.asset.FileAsset(filePath),
        contentType: mime.getType(filePath) || undefined,
        // Optional: Smart cache control for better performance
        cacheControl: s3ObjectKey.startsWith("_nuxt/")
            ? "public, max-age=31536000, immutable" // Cache hash-based assets forever
            : "public, max-age=0, must-revalidate",  // Always revalidate HTML/files
    });
});

// Optional: Add a bucket policy to make your site publicly accessible
const publicBucketPolicy = new aws.s3.BucketPolicy("nuxt-site-public-policy", {
    bucket: siteBucket.bucket,
    policy: siteBucket.bucket.apply(name => JSON.stringify({
        Version: "2012-10-17",
        Statement: [{
            Effect: "Allow",
            Principal: "*",
            Action: "s3:GetObject",
            Resource: `arn:aws:s3:::${name}/*`,
        }],
    })),
});

// Export useful stack outputs
export const bucketName = siteBucket.bucket;
export const staticWebsiteUrl = siteBucket.websiteEndpoint;

Key Improvements Explained

  • Recursive File Traversal: The getAllFiles function digs into every subdirectory of dist, so files like _nuxt/fonts/element-icons.4520188.ttf don’t get missed.
  • Preserved Directory Structure: Using path.relative(distDir, filePath) ensures S3 objects have the same nested path as your local dist files—critical for Nuxt to load assets correctly.
  • Nuxt-Specific Bucket Config: The website settings include 200.html as the error document, which fixes SPA routing issues (Nuxt uses this to handle client-side navigation).
  • Intelligent Cache Control: Hash-named assets in _nuxt/ are cached indefinitely (since their filenames change on rebuild), while HTML files are revalidated every time—optimizing performance without stale content issues.

How to Use

  1. Replace your existing Pulumi code with this snippet.
  2. Run npm run build in your Nuxt project to generate the dist directory.
  3. Deploy with pulumi up—all nested files will be uploaded to S3 automatically.

内容的提问来源于stack exchange,提问作者jonashackt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 15:17:40