Scripts to manage themes in October CMS

Usage no npm install needed!

<script type="module">
  import acantoOctoberScripts from 'https://cdn.skypack.dev/@acanto/october-scripts';


October scripts


First go into the project root directory cd myproject, then:

npm i @acanto/october-scripts --save-dev


First you need to add to your project's package.json the following:

  "scripts": {
    "start": "october-scripts start",
    "test": "october-scripts test",
    "page": "october-scripts page",
    "comp": "october-scripts component",
    "build": "october-scripts build",
    "setup": "october-scripts setup",
    "clean": "october-scripts clean",
    "deploy": "october-scripts deploy"

Then from your root folder you can run:

# install dependencies
npm install

# run local development server with live reload
npm start

# generate a template, style and script for a specific page
npm run page my-page-name

# generate a template, style and script for a specific component
npm run comp my-component-name

# build the production code and start a local server running it
npm run test

# build the production code
npm run build

# clear OctoberCMS caches
npm run clean

# extract class names from page template and generate .scss file
october-scripts extract-page my-page-name


When deploying run:

# install dependencies
npm install

# build the production code ready for deployment
npm run deploy


All gulp configuration is inside a standalone package @acanto/october-scripts published on npm, the project just uses its package.json file to configure and run the scripts. In this way a project have only one devDependency and the scripts can be updated separately from each project, so that every project can benefit from the updates.


This file will be autogenerated if not found trying to guess the values (execpt for the db username and password)

# BROWSER_SYNC_HOST=http://myproject.test
# DB_USERNAME=myuser
# DB_PASSWORD=mypassword


Each project needs to set the homepage entry and can override some basic configurations of the scripts from the config section of it package.json. The following configuration is required and needs to change accordingly to your specific project:

  "homepage": "https://myproject.com",
  "config": {
    "favicons": {
      "background": "#fefefe"

Windows caveats

To run the script on windows you might need to go to System Properties and on Advanced -> Add to Environment variables -> Users -> Path append the following variables:

  • C:\Program Files\Git\cmd in order to be able to install npm packages directly from git remotes instead that from published versions git must be in the path source
  • C:\Program Files\nodejs to run node scripts from the current directory


  • Live reload
  • JS/SCSS modules bundling with webpack
  • SCSS compilation with node-sass and postcss
  • SCSS optimization combining media queries with css-mqpacker
  • ES6 syntax support with babel
  • CSS and JS files automatic splitting and cache busting
  • SCSS and JS sourcemaps
  • Page specific CSS inlining through October's partials
  • Assets minification
  • Images minification with imagemin
  • SVG inline icons automatic generation from svg images
  • Favicons auto-generation from single image with favicons
  • License banner for compiled css and js files
  • Page generator, .js, .scss and .htm templates
  • TODO: Prettier for .htm templates

Folder structure

Each path used in the gulp tasks can be overridden in the specific project package.json file (see notes below), but the ideal and default folder configuration assumed is the following:

      assets/ # compiled files (.gitignored, DO NOT EDIT!)
      layouts/ # twig layout templates
      pages/ # twig page templates
        home.htm # page specific template
      partials/ # twig partials
        automated/ # compiled partials (.gitignored, DO NOT EDIT!)
        components/ # decoupled components to use across pages
          MyComponent.htm # component template
      src/ # sources of the assets that gets compiled
        components/ # decoupled components to use across pages
          MyComponent/ # component folder uses component name
            index.scss # component style
            index.js # component script
        config/ # conguration files
          index.scss # scss config (variables, mixins, functions, ecc.)
          index.js # js config (globals, settings, ecc.)
        pages # page specific and inlined in the corresponding template
          home.scss # page specific and scoped styles
          home.js # page specific and scoped scripts
        utils # utils generic components
          animations.scss # utils like styles
          animations.js # utils simple script
        vendor # custom vendor imports
          package-name.js # customised vendor import script
          package-name.scss # customised vendor import styles
        images/ # all images (will be compressed)
          icons/ # svg images that will be turned automatically in an icon font
        fonts/ # custom fonts for the specific theme
        theme.js # entry point with all js/scss imports

Dev notes

Environment variables

October has a built-in functionality to subsititute the config variables with dotenv-ready code, you can run php artisan october:env from the root. These change some local configuration files, what we are interested in are config/app.php, config/database.php and config/environment.php.

Cache issues

CSS/JS inlining

To inline the shared js/css chunks in the HTML we could simply do this:

use Cms\Classes\Theme;

function onStart() {

  $appCssPath = themes_path(Theme::getActiveThemeCode() . "/assets/styles") . "/theme.css";
  $this['appCssRelativePath'] = '../assets/styles/theme.css';
  $this['appCssFilesize'] = filesize($appCssPath) / 1024;


{% if appCssFilesize < 52 %}
<style>{{ source(appCssRelativePath) }}</style>
{% else %}
<link href="{{ 'assets/styles/theme.5f616e7af5a515c60829.css'|theme }}" rel="stylesheet" />
{% endif %}

but the fonts relative path breaks, we should give the fonts an absolute path depending on the environment. Plus we should generate a non hashed file with webpack and be careful because with this approach we assume there is only one shared/common chunk, but there might be more with js dynamic imports.