Skip to main content
Learn how to compile SCSS, bundle JavaScript, and optimize assets for Zoo Arcadia using Gulp.

Overview

Zoo Arcadia uses Gulp 5 as its build tool to:
  • Compile SCSS to CSS
  • Minify and bundle JavaScript
  • Copy vendor libraries (Bootstrap, jQuery, DataTables)
  • Watch files for automatic rebuilds
  • Serve the application with BrowserSync for live reload

Build Configuration

The build pipeline is configured in gulpfile.js and package.json.

File Structure

zoo-arcadia/
├── gulpfile.js                 # Gulp task definitions
├── package.json                # Node.js dependencies
├── src/                        # Source files
│   ├── scss/
│   │   ├── app.scss           # Main stylesheet
│   │   └── bo-sidebar-only.scss  # Backoffice sidebar
│   └── js/
│       ├── app.js             # Main JavaScript
│       ├── animals-filter.js  # Animal filtering
│       ├── habitat-filter.js  # Habitat filtering
│       └── rating-testimony.js # Testimonial ratings
└── public/
    └── build/                  # Compiled output
        ├── css/
        │   ├── app.css        # Compiled main CSS
        │   ├── bo-sidebar-only.css
        │   ├── bootstrap.min.css
        │   ├── normalize.css
        │   └── dataTables.bootstrap5.min.css
        └── js/
            ├── app.js         # Minified app JS
            ├── animals-filter.js
            ├── habitat-filter.js
            ├── rating-testimony.js
            ├── jquery.min.js
            ├── bootstrap.bundle.min.js
            └── dataTables.min.js

Dependencies

Development Dependencies

Installed via npm install --save-dev:
package.json
{
  "gulp": "^5.0.1",
  "gulp-sass": "^6.0.1",
  "sass": "^1.89.2",
  "gulp-sourcemaps": "^2.6.5",
  "gulp-plumber": "^1.2.1"
}

Production Dependencies

UI frameworks and libraries:
package.json
{
  "dependencies": {
    "bootstrap": "^5.3.7",
    "bootstrap-icons": "^1.13.1",
    "jquery": "^3.7.1",
    "normalize.css": "^8.0.1",
    "datatables.net": "^2.3.4",
    "datatables.net-bs5": "^2.3.4"
  }
}

Gulp Tasks

Build Tasks

Compiles SCSS and copies vendor CSS.
gulpfile.js
const buildCss = series(cleanCss, compileSass, compileBoSidebar, copyVendorCss);
Steps:
  1. cleanCss: Delete public/build/css/
  2. compileSass: Compile src/scss/app.scsspublic/build/css/app.css
  3. compileBoSidebar: Compile src/scss/bo-sidebar-only.scss
  4. copyVendorCss: Copy Bootstrap, Normalize, DataTables CSS
Run:
npx gulp buildCss

File Paths Configuration

Paths are defined at the top of gulpfile.js:
gulpfile.js
const paths = {
    scss: 'src/scss/**/*.scss',
    js: 'src/js/**/*.js',
    vendorJs: [
        'node_modules/jquery/dist/jquery.min.js',
        'node_modules/bootstrap/dist/js/bootstrap.bundle.min.js',
        'node_modules/datatables.net/js/dataTables.min.js',
        'node_modules/datatables.net-bs5/js/dataTables.bootstrap5.min.js'
    ],
    vendorCss: [
        'node_modules/normalize.css/normalize.css',
        'node_modules/bootstrap/dist/css/bootstrap.min.css',
        'node_modules/datatables.net-bs5/css/dataTables.bootstrap5.min.css'
    ]
};

SCSS Compilation

Main Stylesheet

The compileSass task processes src/scss/app.scss:
gulpfile.js
function compileSass() {
  return src('src/scss/app.scss')
    .pipe(plumber())        // Prevent pipe breaking on errors
    .pipe(sass())           // Compile SCSS to CSS
    .pipe(dest('public/build/css'))
    .pipe(browserSync.stream());
}
Key Features:
  • Plumber: Prevents build failures on syntax errors
  • BrowserSync Stream: Injects CSS changes without full page reload

Backoffice Sidebar

A separate stylesheet for the admin sidebar:
gulpfile.js
function compileBoSidebar() {
  return src('src/scss/bo-sidebar-only.scss')
    .pipe(plumber())
    .pipe(sass())
    .pipe(dest('public/build/css'))
    .pipe(browserSync.stream());
}

Vendor CSS

Copies third-party CSS files:
gulpfile.js
function copyVendorCss() {
    return src(paths.vendorCss)
        .pipe(dest('public/build/css'));
}

JavaScript Processing

Custom JavaScript

Each custom JS file is processed separately with sourcemaps and minification:
gulpfile.js
function processJs() {
    // Main app.js
    const appJs = src(['src/js/app.js'])
        .pipe(sourcemaps.init())
        .pipe(terser())  // Minify
        .pipe(sourcemaps.write('.'))
        .pipe(dest('public/build/js'));
    
    // Animals filter
    const animalsFilterJs = src('src/js/animals-filter.js')
        .pipe(sourcemaps.init())
        .pipe(terser())
        .pipe(sourcemaps.write('.'))
        .pipe(dest('public/build/js'));
    
    // ... similar for habitat-filter.js and rating-testimony.js
    
    return require('merge-stream')(appJs, animalsFilterJs, habitatFilterJs, ratingTestimonyJs);
}
Why Separate Files?
  • Allows loading only needed JavaScript per page
  • Reduces initial page load time
  • Easier debugging with sourcemaps

Vendor JavaScript

Copies pre-minified vendor libraries:
gulpfile.js
function copyVendorJs() {
    return src(paths.vendorJs)
        .pipe(dest('public/build/js'));
}

Development Workflow

Watch Mode

The watchAll function monitors files for changes:
gulpfile.js
function watchAll() {
  // Watch SCSS files
  watch(paths.scss, buildCss);
  
  // Watch JS files
  watch(paths.js, series(buildJs, reload));
  
  // Watch PHP files (Frontend and Backend)
  watch('public/**/*.php', reload);
  watch('App/**/*.php', reload);
  watch('includes/**/*.php', reload);
}

BrowserSync Server

Starts a development server with live reload:
gulpfile.js
let currentProxy = 'http://localhost:3001'; // PHP server

function serve(done) {
  browserSync.init({
    proxy: currentProxy,
    open: true,
    notify: true
  });
  done();
}
Setup Requirements:
  1. Start PHP server on port 3001:
    php -S localhost:3001 -t public
    
  2. Run Gulp in another terminal:
    npx gulp
    
  3. BrowserSync opens at http://localhost:3000 (proxies to 3001)

Build Commands

1

Install Dependencies

npm install
2

Build Everything

Build CSS and JavaScript for production:
npx gulp buildCss
npx gulp buildJs
Or use the npm script:
npm run css
3

Development Mode

Start the dev server with watch mode:
npx gulp
This will:
  • Build all assets
  • Start BrowserSync on localhost:3000
  • Watch for file changes
  • Auto-reload browser on changes

Production Build

For production deployments:
1

Clean Install

rm -rf node_modules public/build
npm ci --production=false
2

Build Assets

npx gulp buildCss
npx gulp buildJs
3

Verify Output

Check that files exist:
ls -la public/build/css/
ls -la public/build/js/
The Dockerfile automatically runs these commands during the Docker build process.

Cleaning Output

Clean tasks remove compiled files:
gulpfile.js
function cleanCss() {
  return deleteAsync('./public/build/css');
}

function cleanJs() {
  return deleteAsync('./public/build/js');
}
Manual Cleanup:
rm -rf public/build/css public/build/js

Troubleshooting

Symptoms: Syntax errors or missing importsSolutions:
  • Check SCSS syntax in src/scss/app.scss
  • Ensure sass package is installed: npm install sass
  • Look for typos in @import statements
  • Run with verbose output: npx gulp buildCss --verbose
Symptoms: Terser fails with syntax errorsSolutions:
  • Check JavaScript syntax in src/js/*.js
  • Ensure ES6+ features are supported by your browser target
  • Temporarily disable minification to debug:
    // Comment out terser()
    .pipe(sourcemaps.init())
    // .pipe(terser())
    .pipe(sourcemaps.write('.'))
    
Symptoms: Changes don’t trigger reloadSolutions:
  • Ensure PHP server is running on port 3001
  • Check proxy URL in gulpfile.js matches your PHP server
  • Restart Gulp: Ctrl+C then npx gulp
  • Clear browser cache
Symptoms: Bootstrap or jQuery not loadedSolutions:
  • Run npm install to download vendor libraries
  • Check paths in gulpfile.js match node_modules/ structure
  • Manually run: npx gulp copyVendorCss and npx gulp copyVendorJs
Symptoms: Gulp fails to start or throws errorsSolutions:
  • Ensure Node.js 18 or higher: node --version
  • Update npm: npm install -g npm@latest
  • Clear npm cache: npm cache clean --force
  • Delete and reinstall: rm -rf node_modules && npm install

Advanced Configuration

Custom SCSS Variables

Create src/scss/_variables.scss for custom theming:
// Override Bootstrap variables
$primary: #2c5f2d;
$secondary: #97bc62;
$font-family-base: 'Inter', sans-serif;

// Import Bootstrap
@import '~bootstrap/scss/bootstrap';

Adding New JavaScript Files

To add a new JS file:
  1. Create src/js/my-feature.js
  2. Add to processJs() in gulpfile.js:
gulpfile.js
const myFeatureJs = src('src/js/my-feature.js')
    .pipe(sourcemaps.init())
    .pipe(terser())
    .pipe(sourcemaps.write('.'))
    .pipe(dest('public/build/js'));

return require('merge-stream')(appJs, animalsFilterJs, myFeatureJs, ...);
  1. Include in your HTML:
<script src="/build/js/my-feature.js"></script>

PostCSS and Autoprefixer

For browser prefixes, add PostCSS:
npm install --save-dev gulp-postcss autoprefixer
gulpfile.js
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');

function compileSass() {
  return src('src/scss/app.scss')
    .pipe(sass())
    .pipe(postcss([autoprefixer()]))  // Add vendor prefixes
    .pipe(dest('public/build/css'));
}

Next Steps

Environment Setup

Set up your development environment

Architecture Overview

Learn about the application architecture

Docker Deployment

Build assets in Docker

Database Schema

Explore the database structure

Build docs developers (and LLMs) love