Include non html files with Panini build

I’m using the Foundation Panini library with Foundation for Sites. I’m wondering how to include non-html files in the build when you compile your files. I know I need to probably edit the gulp file. I have a mostly static site with mostly all html files, but a few .cfm pages. I know I can just add includes with the cfm files but since I have mostly html files, I just want to use the same navigation, header, footer, etc “includes”.

But as of right now, only the html files get compiled into the dist folder. How to I get it to compile the cfm files as well?

Please provide the gulpfile that you use. Depending on your gulp tasks, gulp plugins and gulp.src there might be different solutions.

The easiest is a gulp.src + gulp.dest as some copy task.

@DanielRuf What I did actually works, but I’m wondering if there is a better way, because it builds a pages folder inside my dist folder with all duplicate pages in it. So I’m doing something wrong. I tried taking out “pages” in the path name but I didn’t work.

gulp file:
‘use strict’;

import plugins       from 'gulp-load-plugins';
import yargs         from 'yargs';
import browser       from 'browser-sync';
import gulp          from 'gulp';
import panini        from 'panini';
import rimraf        from 'rimraf';
import sherpa        from 'style-sherpa';
import yaml          from 'js-yaml';
import fs            from 'fs';
import webpackStream from 'webpack-stream';
import webpack2      from 'webpack';
import named         from 'vinyl-named';
import uncss         from 'uncss';
import autoprefixer  from 'autoprefixer';

// Load all Gulp plugins into one variable
const $ = plugins();

// Check for --production flag
const PRODUCTION = !!(yargs.argv.production);

// Load settings from settings.yml
const { PORT, UNCSS_OPTIONS, PATHS } = loadConfig();
function loadConfig() {
  let ymlFile = fs.readFileSync('config.yml', 'utf8');
  return yaml.load(ymlFile);

// Build the "dist" folder by running all of the below tasks
// Sass must be run later so UnCSS can search for used classes in the others assets.

 gulp.series(clean, gulp.parallel(pages, javascript, images, copy, copyAudio, copyPDF, copySitemaps, copyPages), sass, styleGuide)); // took out , copyPages

// Build the site, run the server, and watch for file changes


  gulp.series('build', server, watch));

// Delete the "dist" folder

// This happens every time a build starts

function clean(done) {

  rimraf(PATHS.dist, done);


// Copy files out of the assets folder

// This task skips over the "img", "js", and "scss" folders, which are parsed separately

function copy() {

  return gulp.src(PATHS.assets)

    .pipe(gulp.dest(PATHS.dist + '/assets'));


function copyAudio() {

  return gulp.src('src/audio/*')

    .pipe(gulp.dest(PATHS.dist + '/audio'));


function copyPDF() {

  return gulp.src('src/pdfs/*')

    .pipe(gulp.dest(PATHS.dist + '/pdfs'));


function copySitemaps() {

  return gulp.src('src/sitemaps/*')

    .pipe(gulp.dest(PATHS.dist + '/sitemaps'));


function copyPages() {

 return gulp.src(['src/pages/*'])

   .pipe(gulp.dest(PATHS.dist + '/pages'));


// Copy page templates into finished HTML files

function pages() {

  return gulp.src('src/pages/**/*.{html,hbs,handlebars,cfm}')


      root: 'src/pages/',

      layouts: 'src/layouts/',

      partials: 'src/partials/',

      data: 'src/data/',

      helpers: 'src/helpers/'




// Load updated HTML templates and partials into Panini

function resetPages(done) {




// Generate a style guide from the Markdown content and HTML template in styleguide/

function styleGuide(done) {

  sherpa('src/styleguide/', {

    output: PATHS.dist + '/styleguide.html',

    template: 'src/styleguide/template.html'

  }, done);


// Compile Sass into CSS

// In production, the CSS is compressed

function sass() {

  const postCssPlugins = [

    // Autoprefixer


    // UnCSS - Uncomment to remove unused styles in production

    // PRODUCTION && uncss.postcssPlugin(UNCSS_OPTIONS),


  return gulp.src('src/assets/scss/app.scss')



      includePaths: PATHS.sass


      .on('error', $.sass.logError))


    .pipe($.if(PRODUCTION, $.cleanCss({ compatibility: 'ie9' })))

    .pipe($.if(!PRODUCTION, $.sourcemaps.write()))

    .pipe(gulp.dest(PATHS.dist + '/assets/css'))

    .pipe(browser.reload({ stream: true }));


let webpackConfig = {

  mode: (PRODUCTION ? 'production' : 'development'),

  module: {

    rules: [


        test: /\.js$/,

        use: {

          loader: 'babel-loader',

          options: {

            presets: [ "@babel/preset-env" ],

            compact: false






  devtool: !PRODUCTION && 'source-map'


// Combine JavaScript into one file

// In production, the file is minified

function javascript() {

  return gulp.src(PATHS.entries)



    .pipe(webpackStream(webpackConfig, webpack2))

    .pipe($.if(PRODUCTION, $.uglify()

      .on('error', e => { console.log(e); })


    .pipe($.if(!PRODUCTION, $.sourcemaps.write()))

    .pipe(gulp.dest(PATHS.dist + '/assets/js'));


// Copy images to the "dist" folder

// In production, the images are compressed

function images() {

  return gulp.src('src/assets/img/**/*')

    .pipe($.if(PRODUCTION, $.imagemin([

      $.imagemin.jpegtran({ progressive: true }),


    .pipe(gulp.dest(PATHS.dist + '/assets/img'));


// Start a server with BrowserSync to preview the site in

function server(done) {


    server: PATHS.dist, port: PORT

  }, done);


// Reload the browser with BrowserSync

function reload(done) {




// Watch for changes to static assets, pages, Sass, and JavaScript

function watch() {, copy);'src/audio/*', copyAudio);'src/pdfs/*', copyPDF);'src/sitemaps/*', copySitemaps);'src/pages/*.cfm', copyPages);'src/pages/**/*.html').on('all', gulp.series(pages, browser.reload));'src/{layouts,partials}/**/*.html').on('all', gulp.series(resetPages, pages, browser.reload));'src/data/**/*.{js,json,yml}').on('all', gulp.series(resetPages, pages, browser.reload));'src/helpers/**/*.js').on('all', gulp.series(resetPages, pages, browser.reload));'src/assets/scss/**/*.scss').on('all', sass);'src/assets/js/**/*.js').on('all', gulp.series(javascript, browser.reload));'src/assets/img/**/*').on('all', gulp.series(images, browser.reload));'src/styleguide/**').on('all', gulp.series(styleGuide, browser.reload));


@DanielRuf I posted my code for the gulp file. Just wondering if you could take a look and see if I’m doing it right, or is there a better way to get .cfm files into my build?

Please keep in mind that we had holidays. No, I had not yet the time to take a closer look / test it.

Yes, sorry. Waited to check til after holidays. I know you’re super busy too. No problem.

//gulp 4.0.2 panini 1.6.3
gulp.task('compile-html', function(){
    var paniniOption = {
        root: 'src/html/pages/',
        layouts: 'src/html/layouts/',
        partials: 'src/html/includes/',
        helpers: 'src/html/helpers/',
        data: 'src/html/data/'
    return gulp.src('src/html/pages/**/*.html')
});'src/html/pages/**/*').on('change', gulp.series('compile-html', browserSync.reload));'src/html/{layouts,includes,helpers,data}/**/*').on('change', gulp.series(async () => { await panini.refresh() }, 'compile-html', browserSync.reload));

I’m not familiar with .cfm files, but I have used a combination of html and php files. I don’t know if this will help, but here is what I did. I made the following changes to the file gulpfile.babel.js:

//  add php to the list of file extensions in src/pages
function pages() {
  return gulp.src('src/pages/**/*.{html,php,hbs,handlebars}')
      root: 'src/pages/',
      layouts: 'src/layouts/',
      partials: 'src/partials/',
      data: 'src/data/',
      helpers: 'src/helpers/'


// watch php as well as html files in src/pages for changes, copy);'src/pages/**/*.html').on('all', gulp.series(pages, browser.reload));'src/pages/**/*.php').on('all', gulp.series(pages, browser.reload));

For pure php files that don’t contain any html, I put them in the folder src/assets/php that I created. They are copied unchanged to the same folder in dist.