Q:

Gulp task to replace all Root-Relative URLs with Document-Relative URLs

There are 4 distinct URL types;

Absolute http://www.example.com/images/icons.png
Document-Relative ../images/icons.png
Root-Relative /images/icons.png
Protocol-Relative //www.example.com/images/icons.png

I have a large static file site (html, css, js) which is built with Jigsaw. This framework takes PHP templates and compiles them into static HTML. I am also using Gulp tasks to compile assets (sass, js..etc).
Using Jigsaw's build process I can either have the site built with full Absolute paths/urls (http://example.com/path-to/page) or Root-Relative (/path-to/page).
This is great but now the client wants the site to use Document-Relative as they are now hosting the site in a subdirectory with a URL pointing to that subdirectory.
E.g. http://example.com would point to http://xx.server.com/hosted-files/directory
My issue is that Jigsaw doesn't allow for Document-Relative URLs. Is there a gulp/node script I can use to convert all references (image sources, links, css paths..etc)? Or is there another solution (e.g. using .htacccess)?
TLDR;
I need to replace any Absolute or Root-Relative references in multiple HTML files and directories with Document-Relative paths and URLs. Or is there another solution (e.g. using .htacccess)?

A:

I have managed to solve my own issue with what I feel is a "hacky" fix.
I've basically created a custom gulp plugin replaces URLs/paths..etc with Document-Relative paths.
gulpfile.js - relative-urls task runs after all other tasks have completed.
const relative = require('./tasks/document-relative');
gulp.task('relative-urls', function() {
    return gulp.src('build/**/*.html')
        .pipe( relative({
            directory: 'build',
            url: 'http://localhost:8000',
        }) )
        .pipe( gulp.dest('build') );
});

./tasks/document-relative.js - plugin
'use strict';

const fs            = require('fs');
const PluginError   = require('plugin-error');
const through       = require('through2');

const PLUGIN_NAME   = 'document-relative';

let count = 0;

module.exports = function(options) {

    // Remove slashes from beginning and end of string
    const strip_slashes = (string) => {
        return string ? string.replace(/^\/|\/$/g, '') : null;
    }

    // Users options object
    options = options || {};

    // Cleanup options
    const base_dir  = strip_slashes(options.directory);
    const url       = strip_slashes(options.url) + '/';

    return through({
        objectMode: true,
        writable: true,
        readable: true
    },
    function(file, enc, callback) {
        count++;

        // Check for null file
        if (file.isNull()) {
            return callback(null, file);
        }

        if (file.isStream()) {
            this.emit('error', new PluginError(PLUGIN_NAME, 'Stream not supported!'));
            return callback(null, file);
        }

        if (file.isBuffer()) {

            // Get contents of this file
            let html        = file.contents.toString(enc);

            // This files full path (/home/usr/project/build/page/example/index.html)
            const path      = file.path;

            // Path task was run from (/home/usr/project/)
            const cwd       = file.cwd+( base_dir ? '/'+base_dir : '' );

            // Project specific path (/page/example/index.html)
            const relative  = path.replace(cwd, '');

            // Get array of directories ['page', 'example', 'index.html']
            let paths       = strip_slashes(relative).split('/');

            // Remove last item ['page', 'example']
            paths.pop();

            // Add ../ for nth number of paths in array
            let rel_path    = paths.length === 0 ? '' : ('../'.repeat(paths.length));

            // Replace dom attributes (e.g. href="/page/example")
            html = html.replace( /(?:(?!="\/\/)="\/)/g, '="'+rel_path );

            // Replace inline background (e.g. background: url('/image/something.jpg'))
            html = html.replace( /url\(\'\//g, 'url(\''+rel_path );
            html = html.replace( /url\(&#039;\//g, 'url(&#039;'+rel_path );

            // If user defined URL, match and remove
            if (url && url.length) {
                html = html.replace( new RegExp(url, 'g'), rel_path );
            }

            // Overwrite file
            fs.writeFileSync(file.path, html, {
                encoding: enc,
                flag:'w'
            });

            return callback();
        }
    });
};

This basically opens all .html files in my build folder, calculates how many paths deep each file is (/folder1/folder2/index.html) and replaces any instances of url (http://localhost:8000) with ../ repeated for the number of paths calculated.

