To create a React-TypeScript application, deploy it to an S3 bucket, and make it publicly accessible using the AWS SDK, follow these steps:
-
Create a React-TypeScript app using
create-react-app
:npx create-react-app my-react-ts-app --template typescript cd my-react-ts-app
-
Run the app locally to ensure it works:
npm start
-
Build the app for production:
npm run build
This generates a
build
folder containing the production-ready files.
-
Install the AWS SDK for JavaScript:
npm install aws-sdk
-
Configure AWS credentials:
- Create an IAM user with the following permissions:
AmazonS3FullAccess
- Generate access keys for the IAM user.
- Configure the AWS CLI or SDK with the credentials:
Provide the access key, secret key, region (e.g.,
aws configure
us-east-1
), and default output format (e.g.,json
).
- Create an IAM user with the following permissions:
-
Create an S3 bucket using the AWS SDK: Create a script (e.g.,
deploy.js
) to create the bucket and upload files:const AWS = require('aws-sdk'); const fs = require('fs'); const path = require('path'); // Configure AWS SDK AWS.config.update({ region: 'us-east-1' }); const s3 = new AWS.S3(); // Bucket name (must be unique globally) const bucketName = 'my-react-ts-app-bucket'; // Function to create S3 bucket const createBucket = async () => { try { await s3.createBucket({ Bucket: bucketName }).promise(); console.log(`Bucket created: ${bucketName}`); } catch (err) { console.error('Error creating bucket:', err); } }; // Function to upload files to S3 const uploadFiles = async () => { const buildFolder = path.join(__dirname, 'build'); const files = fs.readdirSync(buildFolder); for (const file of files) { const filePath = path.join(buildFolder, file); const fileContent = fs.readFileSync(filePath); const params = { Bucket: bucketName, Key: file, Body: fileContent, ContentType: file.endsWith('.html') ? 'text/html' : file.endsWith('.css') ? 'text/css' : 'application/javascript', }; try { await s3.upload(params).promise(); console.log(`Uploaded: ${file}`); } catch (err) { console.error(`Error uploading ${file}:`, err); } } }; // Run the deployment (async () => { await createBucket(); await uploadFiles(); })();
-
Run the script:
node deploy.js
-
Enable static website hosting: Update the bucket policy to allow public read access:
const makeBucketPublic = async () => { const bucketPolicy = { Version: '2012-10-17', Statement: [ { Sid: 'PublicReadGetObject', Effect: 'Allow', Principal: '*', Action: 's3:GetObject', Resource: `arn:aws:s3:::${bucketName}/*`, }, ], }; const params = { Bucket: bucketName, Policy: JSON.stringify(bucketPolicy), }; try { await s3.putBucketPolicy(params).promise(); console.log('Bucket policy updated to public.'); } catch (err) { console.error('Error updating bucket policy:', err); } }; // Add this to the deployment script (async () => { await createBucket(); await uploadFiles(); await makeBucketPublic(); })();
-
Enable static website hosting: Update the bucket to host a static website:
const enableStaticWebsiteHosting = async () => { const params = { Bucket: bucketName, WebsiteConfiguration: { ErrorDocument: { Key: 'index.html', }, IndexDocument: { Suffix: 'index.html', }, }, }; try { await s3.putBucketWebsite(params).promise(); console.log('Static website hosting enabled.'); } catch (err) { console.error('Error enabling static website hosting:', err); } }; // Add this to the deployment script (async () => { await createBucket(); await uploadFiles(); await makeBucketPublic(); await enableStaticWebsiteHosting(); })();
-
Get the public URL: The public URL for your S3-hosted website will be:
http://<bucket-name>.s3-website-<region>.amazonaws.com
Example:
http://my-react-ts-app-bucket.s3-website-us-east-1.amazonaws.com
-
Open the URL in your browser to see your React-TypeScript app.
You can automate the deployment process by adding the script to your package.json
:
"scripts": {
"deploy": "npm run build && node deploy.js"
}
Run the deployment with:
npm run deploy
If you no longer need the bucket, delete it to avoid unnecessary charges:
const deleteBucket = async () => {
try {
await s3.deleteBucket({ Bucket: bucketName }).promise();
console.log(`Bucket deleted: ${bucketName}`);
} catch (err) {
console.error('Error deleting bucket:', err);
}
};
// Add this to the deployment script if needed
(async () => {
await deleteBucket();
})();
This process will deploy your React-TypeScript app to an S3 bucket and make it publicly accessible.
const AWS = require('aws-sdk');
const fs = require('fs');
const path = require('path');
// Configure AWS SDK
AWS.config.update({ region: 'us-east-1' });
const s3 = new AWS.S3();
// Bucket name (must be unique globally)
const bucketName = 'my-react-ts-app-bucket';
// Function to create S3 bucket (if it doesn't exist)
const createBucket = async () => {
try {
await s3.createBucket({ Bucket: bucketName }).promise();
console.log(`Bucket created: ${bucketName}`);
} catch (err) {
if (err.code !== 'BucketAlreadyOwnedByYou') {
console.error('Error creating bucket:', err);
}
}
};
// Function to list all objects in the bucket
const listObjects = async () => {
try {
const data = await s3.listObjectsV2({ Bucket: bucketName }).promise();
return data.Contents || [];
} catch (err) {
console.error('Error listing objects:', err);
return [];
}
};
// Function to move objects to a backup directory
const moveObjectsToBackup = async (objects, backupDir) => {
for (const object of objects) {
const copyParams = {
Bucket: bucketName,
CopySource: `${bucketName}/${object.Key}`,
Key: `${backupDir}/${object.Key}`,
};
const deleteParams = {
Bucket: bucketName,
Key: object.Key,
};
try {
// Copy object to backup directory
await s3.copyObject(copyParams).promise();
console.log(`Copied to backup: ${object.Key}`);
// Delete original object
await s3.deleteObject(deleteParams).promise();
console.log(`Deleted original: ${object.Key}`);
} catch (err) {
console.error(`Error moving ${object.Key}:`, err);
}
}
};
// Function to upload new files to S3
const uploadFiles = async () => {
const distFolder = path.join(__dirname, 'dist');
const files = fs.readdirSync(distFolder);
for (const file of files) {
const filePath = path.join(distFolder, file);
const fileContent = fs.readFileSync(filePath);
const params = {
Bucket: bucketName,
Key: file,
Body: fileContent,
ContentType: file.endsWith('.html') ? 'text/html' : file.endsWith('.css') ? 'text/css' : 'application/javascript',
};
try {
await s3.upload(params).promise();
console.log(`Uploaded: ${file}`);
} catch (err) {
console.error(`Error uploading ${file}:`, err);
}
}
};
// Function to make the bucket publicly accessible
const makeBucketPublic = async () => {
const bucketPolicy = {
Version: '2012-10-17',
Statement: [
{
Sid: 'PublicReadGetObject',
Effect: 'Allow',
Principal: '*',
Action: 's3:GetObject',
Resource: `arn:aws:s3:::${bucketName}/*`,
},
],
};
const params = {
Bucket: bucketName,
Policy: JSON.stringify(bucketPolicy),
};
try {
await s3.putBucketPolicy(params).promise();
console.log('Bucket policy updated to public.');
} catch (err) {
console.error('Error updating bucket policy:', err);
}
};
// Function to enable static website hosting
const enableStaticWebsiteHosting = async () => {
const params = {
Bucket: bucketName,
WebsiteConfiguration: {
ErrorDocument: {
Key: 'index.html',
},
IndexDocument: {
Suffix: 'index.html',
},
},
};
try {
await s3.putBucketWebsite(params).promise();
console.log('Static website hosting enabled.');
} catch (err) {
console.error('Error enabling static website hosting:', err);
}
};
// Run the deployment
(async () => {
try {
// Create bucket if it doesn't exist
await createBucket();
// List existing objects in the bucket
const objects = await listObjects();
if (objects.length > 0) {
// Create a timestamped backup directory
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupDir = `backup/${timestamp}`;
// Move existing objects to the backup directory
await moveObjectsToBackup(objects, backupDir);
}
// Upload new files
await uploadFiles();
// Make the bucket publicly accessible
await makeBucketPublic();
// Enable static website hosting
await enableStaticWebsiteHosting();
console.log('Deployment completed successfully!');
} catch (err) {
console.error('Deployment failed:', err);
}
})();