ba-web-components/gulpfile.mjs
Alan Bridgeman 5024375e20
Some checks failed
Build, Test, and Publish (to Private NPM Registry) UI Components Library / publish (push) Failing after 52m26s
Inital code commit
2026-05-13 01:39:35 -05:00

216 lines
No EOL
8.6 KiB
JavaScript

import { spawn } from 'child_process';
import path from 'path';
import fs from 'fs';
import gulp from "gulp";
import rename from 'gulp-rename';
import { deleteAsync } from 'del';
import replace from 'gulp-replace';
import postcss from 'gulp-postcss';
import atImport from 'postcss-import';
import presetEnv from 'postcss-preset-env';
import cssnano from 'cssnano';
// Task which would delete the old dist directory if present
gulp.task("build-clean", () => {
return deleteAsync(["./dist"]);
});
// Task which would transpile typescript to javascript
gulp.task("typescript", (done) => {
const tsconfigPath = path.resolve(path.join('.', 'tsconfig.build.json'));
let proc;
if(process.platform === 'win32') {
proc = spawn('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', 'yarn', 'tsgo', '-p', `"${tsconfigPath}"`], { stdio: 'inherit' });
}
else {
proc = spawn('yarn', ['tsgo', '-p', `${tsconfigPath}`], { stdio: 'inherit' });
}
proc.on('close', code => {
if (code !== 0) {
return done(new Error(`tsgo process exited with code ${code}`));
}
done();
});
});
// Task which would bundle and minify the client-side JavaScript using Rollup
gulp.task("bundle-minify-js", (done) => {
const scriptFiles = [];
fs.readdirSync(path.join('src', 'components')).forEach(component => {
// Check the current item is a directory (i.e., a component folder)
if (fs.statSync(path.join('src', 'components', component)).isDirectory()) {
fs.readdirSync(path.join('src', 'components', component)).forEach(file => {
const componentScriptFiles = [];
// Include any JS files found in a "scripts" subfolder of the component
if(file === 'scripts' && fs.statSync(path.join('src', 'components', component, file)).isDirectory()) {
fs.readdirSync(path.join('src', 'components', component, file)).forEach(scriptFile => {
if(scriptFile.endsWith('.js')) {
scriptFiles.push(path.join('src', 'components', component, 'scripts', scriptFile));
}
});
}
// Look for *.js files inside the root of the component folders
if (file.endsWith('.js')) {
scriptFiles.push(path.join('src', 'components', component, file));
}
scriptFiles.push(...componentScriptFiles);
});
}
});
let clientEntryJSContent = '';
scriptFiles.forEach(scriptFile => {
const relativePath = path.relative(path.join('src', 'components'), scriptFile).replace(/\\/g, '/');
clientEntryJSContent += `import './${relativePath}';\n`;
});
fs.writeFileSync(path.join('src', 'components', 'client-entry.js'), clientEntryJSContent);
let proc;
if(process.platform === 'win32') {
proc = spawn('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', 'yarn', 'rollup', '-c'], { stdio: 'inherit' });
}
else {
proc = spawn('yarn', ['rollup', '-c'], { stdio: 'inherit' });
}
proc.on('close', code => {
// Clean up the temporary entry file so tht the src/ directory stays pristine
const entryPath = path.join('src', 'components', 'client-entry.js');
if (fs.existsSync(entryPath)) {
fs.rmSync(entryPath);
}
if (code !== 0) {
return done(new Error(`Rollup process exited with code ${code}`));
}
done();
});
});
// Task which would just create a copy of the current views directory in dist directory
gulp.task("copy-ejs", function () {
return gulp.src("./src/components/**/*.ejs")
.pipe(rename((parsedPath) => {
// `parsedPath.dirname` is the path relative to the glob base ("./src/components/")
// Example A: "tooltip"
// Example B: "tabs/templates" (or "tabs\templates" on Windows)
// Normalize the slashes to forward slashes to prevent Windows path bugs
const normalizedDir = parsedPath.dirname.replace(/\\/g, '/');
const pathParts = normalizedDir.split('/');
// The first folder level is always your component's name
const componentName = pathParts[0];
// If the path includes a 'templates' directory, it's a complex component
if (pathParts.includes('templates')) {
// Keep the file inside a folder named after the component
// This outputs to: dist/components/tabs/tab-content.ejs
parsedPath.dirname = componentName;
}
else {
// It's a simple component. Flatten it completely.
// This outputs to: dist/components/tooltip.ejs
parsedPath.dirname = '';
}
}))
.pipe(gulp.dest("./dist/components"));
});
// Task which will copy the assets from the static CSS directory to the dist directory
gulp.task("process-css", () => {
// Gather all the component CSS files
const styleFiles = [];
fs.readdirSync(path.join('src', 'components')).forEach(component => {
// Check the current item is a directory (i.e., a component folder)
if (fs.statSync(path.join('src', 'components', component)).isDirectory()) {
fs.readdirSync(path.join('src', 'components', component)).forEach(file => {
const componentStyleFiles = [];
// Include any JS files found in a "styles" subfolder of the component
if(file === 'styles' && fs.statSync(path.join('src', 'components', component, file)).isDirectory()) {
fs.readdirSync(path.join('src', 'components', component, file)).forEach(styleFile => {
if(styleFile.endsWith('.css')) {
componentStyleFiles.push(path.join('src', 'components', component, 'styles', styleFile));
}
});
}
// Look for *.css files inside the root of the component folders
if (file.endsWith('.css')) {
componentStyleFiles.push(path.join('src', 'components', component, file));
}
styleFiles.push(...componentStyleFiles);
});
}
});
const libraryCSSAppendContent = styleFiles.map(styleFile => {
const relativePath = path.relative(path.join('src', 'components'), styleFile).replace(/\\/g, '/');
return `@import "./${relativePath}";`;
}).join('\n');
return gulp.src("./src/components/import.css")
.pipe(replace(/\/\* Component Styles \*\//g, libraryCSSAppendContent))
.pipe(
postcss([
atImport(), // Resolves @import paths (including node_modules)
presetEnv({
stage: 1, // Allows use of future CSS features today
features: {
'nesting-rules': true // Allows SCSS-like nesting natively
}
}),
cssnano({
preset: [
'default', {
calc: false
}
]
})
])
)
.on('error', function(error) {
console.error("\n❌ CSS Error:", error.message);
// Optionally print the code snippet if available
if (error.source) {
console.error(" File:", error.file);
console.error(" Line:", error.line);
}
this.emit('end'); // Prevents Gulp from crashing completely
})
.pipe(rename('components.css'))
.pipe(gulp.dest("./dist/client"));
});
// The default task which runs at start of the gulpfile.js
gulp.task("default", gulp.series("build-clean", "typescript", "bundle-minify-js", "copy-ejs", "process-css"), () => {
console.log("Done");
});
gulp.task('copy-package-files', () => {
// After the default build tasks are done, we can copy the package.json, README.md, and LICENSE to the dist directory for npm publishing
return gulp.src(["./package.lib.json", "./README.md", "./LICENSE"])
.pipe(rename((path) => {
if(path.basename === "package.lib") {
path.basename = "package";
}
}))
.pipe(gulp.dest("./dist"));
});
gulp.task('package', gulp.series('default', 'copy-package-files'), () => {
console.log("Package ready in dist/ directory");
});