updated build process

This commit is contained in:
Dustin Farley
2025-12-06 10:45:53 -08:00
parent 27d63583a5
commit e3092776bf
12 changed files with 201 additions and 46 deletions

View File

@@ -8,18 +8,21 @@ This workflow automatically builds and deploys the project to GitHub Pages whene
1. **Build Stage:**
- Checks out the repository
- Sets up Node.js (v18)
- Sets up Node.js (v20) with npm cache enabled
- Installs dependencies with `npm ci`
- Runs test suite with `npm run test:all`
- Runs `npm run build` which:
- Copies static files to `dist/` (`copy-static.js`)
- Builds transformer index (`build-index.js`)
- Bundles all transformers (`build-transforms.js`)
- Generates emoji data (`build-emoji-data.js`)
- Bundles all transformers to `dist/js/bundles/` (`build-transforms.js`)
- Generates emoji data to `dist/js/data/` (`build-emoji-data.js`)
- Injects tool scripts (`inject-tool-scripts.js`)
- Injects tool templates into `index.html` (`inject-tool-templates.js`)
- Uploads the entire project as a Pages artifact
- Injects tool templates into `dist/index.html` (`inject-tool-templates.js`)
- Verifies critical build files exist in `dist/`
- Uploads only the `dist/` folder as a Pages artifact (7-day retention)
2. **Deploy Stage:**
- Deploys the artifact to GitHub Pages
- Deploys the `dist/` artifact to GitHub Pages
- Makes the site available at your GitHub Pages URL
### Manual Deployment
@@ -40,9 +43,11 @@ The site will be available at: `https://<username>.github.io/<repository-name>/`
### Troubleshooting
- **Build fails**: Check the Actions tab for error logs
- **Tests fail**: Run `npm run test:all` locally to debug issues
- **Missing templates**: Ensure all templates exist in `templates/` directory
- **Test locally first**: Run `npm run build:templates` before pushing to catch errors early
- **Verify build output**: Check that `index.html` contains injected templates after build
- **Test locally first**: Run `npm run build` before pushing to catch errors early
- **Verify build output**: Check that `dist/index.html` and other files exist in `dist/` folder after build
- **Build timeout**: Build has a 10-minute timeout; if it exceeds this, check for infinite loops or large file processing
### Workflow Triggers

View File

@@ -20,6 +20,7 @@ concurrency:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
@@ -28,21 +29,33 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test:all
- name: Build project
run: |
echo "Running full build..."
npm run build
echo "Build complete!"
- name: Verify build output
run: |
test -f dist/index.html || (echo "❌ dist/index.html missing!" && exit 1)
test -f dist/js/bundles/transforms-bundle.js || (echo "❌ dist/js/bundles/transforms-bundle.js missing!" && exit 1)
test -f dist/js/data/emojiData.js || (echo "❌ dist/js/data/emojiData.js missing!" && exit 1)
echo "✅ All critical build files present"
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: '.'
path: 'dist/'
retention-days: 7
deploy:
environment:

2
.gitignore vendored
View File

@@ -10,7 +10,7 @@ dist/
.cache/
*.log
# Generated files
# Generated files (now in dist/, but keeping for backwards compatibility)
index.html
src/transformers/index.js
js/bundles/transforms-bundle.js

View File

@@ -106,7 +106,7 @@ A powerful web-based text transformation and steganography tool that can encode/
### **Quick Start (Built Version)**
1. Run the build process (see Development Setup below)
2. Open `index.html` in any modern web browser
2. Open `dist/index.html` in any modern web browser
3. Type text in the input field
4. Choose a transformation from the categorized buttons
5. Click any transform button to apply and auto-copy
@@ -118,15 +118,17 @@ A powerful web-based text transformation and steganography tool that can encode/
npm install
# Build all assets (required before use):
# - Copies static files to dist/
# - Builds transform bundle from source files
# - Generates emoji data
# - Injects tool templates into index.html
# - Injects tool templates into dist/index.html
npm run build
# Or build individual components:
npm run build:transforms # Bundle all transformers
npm run build:emoji # Generate emoji data
npm run build:templates # Inject tool HTML templates
npm run build:copy # Copy static files to dist/
npm run build:transforms # Bundle all transformers to dist/js/bundles/
npm run build:emoji # Generate emoji data to dist/js/data/
npm run build:templates # Inject tool HTML templates to dist/index.html
npm run build:index # Generate transformer index
# Run tests

View File

@@ -2,10 +2,22 @@
## Scripts
### `build-transforms.js`
Bundles all transformers from `src/transformers/` into `js/bundles/transforms-bundle.js`
### `copy-static.js`
Copies static files to `dist/` directory
- Automatically creates the `js/bundles/` directory if it doesn't exist
- Copies `css/` directory to `dist/css/`
- Copies `favicon.svg` to `dist/favicon.svg`
- Copies `js/` directory structure to `dist/js/`
- Generated files will be overwritten by subsequent build steps
```bash
npm run build:copy
```
### `build-transforms.js`
Bundles all transformers from `src/transformers/` into `dist/js/bundles/transforms-bundle.js`
- Automatically creates the `dist/js/bundles/` directory if it doesn't exist
- Discovers all transformers from category directories
- Generates a single bundled file for browser use
@@ -14,9 +26,9 @@ npm run build:transforms
```
### `build-emoji-data.js`
Fetches Unicode emoji data and generates `js/data/emojiData.js`
Fetches Unicode emoji data and generates `dist/js/data/emojiData.js`
- Automatically creates the `js/data/` directory if it doesn't exist
- Automatically creates the `dist/js/data/` directory if it doesn't exist
- Uses cached data if available (7-day cache)
- Merges keywords from `src/emojiWordMap.js`
@@ -34,7 +46,10 @@ npm run build:tools
```
### `inject-tool-templates.js`
Injects tool templates from `templates/` into `index.html`
Injects tool templates from `templates/` into `dist/index.html`
- Reads from `index.template.html` (source file)
- Outputs to `dist/index.html` (production file)
```bash
npm run build:templates
@@ -51,11 +66,30 @@ npm run build:index
```bash
npm run build # Runs all scripts in order:
# 1. build:index
# 2. build:transforms
# 3. build:emoji
# 4. build:tools
# 5. build:templates
# 1. build:copy - Copy static files to dist/
# 2. build:index - Generate transformer index
# 3. build:transforms - Bundle transformers to dist/js/bundles/
# 4. build:emoji - Generate emoji data to dist/js/data/
# 5. build:tools - Inject tool scripts
# 6. build:templates - Inject templates to dist/index.html
```
## Output Structure
All production files are output to the `dist/` directory:
```
dist/
├── index.html # Generated from index.template.html
├── favicon.svg # Copied from root
├── css/ # Copied from root
│ ├── style.css
│ └── notification.css
└── js/ # Copied from root, then generated files added
├── bundles/
│ └── transforms-bundle.js # Generated
└── data/
└── emojiData.js # Generated
```
## Development Workflow
@@ -63,4 +97,11 @@ npm run build # Runs all scripts in order:
- **Edit transformers** → `npm run build:transforms`
- **Add new tool** → `npm run build:tools`
- **Edit templates** → `npm run build:templates`
- **Full rebuild** → `npm run build`
- **Full rebuild** → `npm run build` (outputs to `dist/` folder)
## Production Deployment
The `dist/` folder contains all files needed for production deployment. This folder is:
- Generated by the build process
- Ignored by git (see `.gitignore`)
- Uploaded to GitHub Pages during CI/CD

View File

@@ -376,7 +376,7 @@ function mergeKeywords(baseKeywords, wordMapKeywords) {
* Generate the emojiData.js file
*/
function generateEmojiDataFile(emojiData) {
const outputPath = path.join(__dirname, '..', 'js', 'data', 'emojiData.js');
const outputPath = path.join(__dirname, '..', 'dist', 'js', 'data', 'emojiData.js');
// Ensure data directory exists
const dataDir = path.dirname(outputPath);

View File

@@ -120,7 +120,7 @@ window.encoders = transforms; // Alias for compatibility
`;
// Write the bundled file
const outputPath = path.join(__dirname, '..', 'js', 'bundles', 'transforms-bundle.js');
const outputPath = path.join(__dirname, '..', 'dist', 'js', 'bundles', 'transforms-bundle.js');
const outputDir = path.dirname(outputPath);
// Ensure the directory exists

92
build/copy-static.js Normal file
View File

@@ -0,0 +1,92 @@
#!/usr/bin/env node
/**
* Copy static files to dist/ directory
* Copies css/, favicon.svg, and js/ directory structure to dist/
* Generated files will be overwritten by build scripts
*/
const fs = require('fs');
const path = require('path');
console.log('📦 Copying static files to dist/...\n');
const projectRoot = path.join(__dirname, '..');
const distDir = path.join(projectRoot, 'dist');
// Ensure dist directory exists
if (!fs.existsSync(distDir)) {
fs.mkdirSync(distDir, { recursive: true });
}
/**
* Recursively copy directory
*/
function copyDirectory(src, dest) {
if (!fs.existsSync(src)) {
console.log(`⚠️ Warning: ${src} not found, skipping...`);
return;
}
// Create destination directory
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest, { recursive: true });
}
const entries = fs.readdirSync(src, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (entry.isDirectory()) {
copyDirectory(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}
}
/**
* Copy a single file
*/
function copyFile(src, dest) {
if (!fs.existsSync(src)) {
console.log(`⚠️ Warning: ${src} not found, skipping...`);
return;
}
const destDir = path.dirname(dest);
if (!fs.existsSync(destDir)) {
fs.mkdirSync(destDir, { recursive: true });
}
fs.copyFileSync(src, dest);
}
// Copy css/ directory
console.log('📁 Copying css/ directory...');
copyDirectory(
path.join(projectRoot, 'css'),
path.join(distDir, 'css')
);
console.log('✅ css/ copied');
// Copy favicon.svg
console.log('📄 Copying favicon.svg...');
copyFile(
path.join(projectRoot, 'favicon.svg'),
path.join(distDir, 'favicon.svg')
);
console.log('✅ favicon.svg copied');
// Copy js/ directory (excluding generated files that will be overwritten)
console.log('📁 Copying js/ directory...');
copyDirectory(
path.join(projectRoot, 'js'),
path.join(distDir, 'js')
);
console.log('✅ js/ copied (generated files will be overwritten by build scripts)');
console.log('\n✨ Static files copied to dist/');
console.log(' Note: Generated files (transforms-bundle.js, emojiData.js, index.html) will be created/overwritten by build scripts\n');

View File

@@ -40,7 +40,7 @@ templateFiles.forEach(templateFile => {
// Read index.template.html (base template)
const templatePath = path.join(__dirname, '../index.template.html');
const indexPath = path.join(__dirname, '../index.html');
const indexPath = path.join(__dirname, '../dist', 'index.html');
if (!fs.existsSync(templatePath)) {
console.error('\n❌ index.template.html not found!');
@@ -76,6 +76,12 @@ const oldSize = indexContent.length;
const newSize = newContent.length;
const sizeDiff = newSize - oldSize;
// Ensure dist directory exists
const distDir = path.dirname(indexPath);
if (!fs.existsSync(distDir)) {
fs.mkdirSync(distDir, { recursive: true });
}
// Write back
fs.writeFileSync(indexPath, newContent, 'utf8');

View File

@@ -3,12 +3,13 @@
"version": "1.0.0",
"description": "Universal Text Encoder/Decoder & Steganography Tool",
"scripts": {
"build:copy": "node build/copy-static.js",
"build:index": "node build/build-index.js",
"build:tools": "node build/inject-tool-scripts.js",
"build:templates": "node build/inject-tool-templates.js",
"build:emoji": "node build/build-emoji-data.js",
"build:transforms": "node build/build-transforms.js",
"build": "npm run build:index && npm run build:transforms && npm run build:emoji && npm run build:tools && npm run build:templates",
"build": "npm run build:copy && npm run build:index && npm run build:transforms && npm run build:emoji && npm run build:tools && npm run build:templates",
"test": "node tests/test_universal.js",
"test:universal": "node tests/test_universal.js",
"test:steg": "node tests/test_steganography_options.js",

View File

@@ -58,7 +58,7 @@ function loadEmojiData() {
// Create a mock window object with necessary properties
const mockWindow = {
emojiLibrary: {
EmojiUtils: {
splitEmojis: function(text) {
// Simple emoji splitting - if Intl.Segmenter is available, use it
if (typeof Intl !== 'undefined' && Intl.Segmenter) {
@@ -67,6 +67,12 @@ const mockWindow = {
}
// Fallback to Array.from for basic splitting
return Array.from(text);
},
joinEmojis: function(emojis) {
return emojis.join('');
},
getAllEmojis: function() {
return Object.keys(mockWindow.emojiData || {});
}
},
emojiData: loadEmojiData()

View File

@@ -18,23 +18,16 @@ const vm = require('vm');
// Get project root directory (parent of tests directory)
const projectRoot = path.resolve(__dirname, '..');
// Load transforms
const transforms = require(path.join(projectRoot, 'src/transformers/loader-node.js'));
// Load decoder
const decoderCode = fs.readFileSync(path.join(projectRoot, 'js/core/decoder.js'), 'utf8');
// Load emoji dependencies
const emojiLibraryCode = fs.readFileSync(path.join(projectRoot, 'js/core/emojiLibrary.js'), 'utf8');
const emojiWordMapCode = fs.readFileSync(path.join(projectRoot, 'src/emojiWordMap.js'), 'utf8');
const emojiUtilsCode = fs.readFileSync(path.join(projectRoot, 'js/utils/emoji.js'), 'utf8');
// Create mock window/steganography objects
const mockSteganography = {
decodeEmoji: (text) => null,
decodeInvisible: (text) => null
};
// Create sandbox for decoder
const sandbox = {
window: {
transforms: transforms,
@@ -51,12 +44,8 @@ const sandbox = {
};
vm.createContext(sandbox);
// Load emoji library and keywords
vm.runInContext(emojiLibraryCode, sandbox);
vm.runInContext(emojiUtilsCode, sandbox);
vm.runInContext(emojiWordMapCode, sandbox);
// Load decoder
vm.runInContext(decoderCode, sandbox);
const universalDecode = sandbox.universalDecode;