Slicejack / bojler

Bojler is an email framework
https://bojler.slicejack.com
MIT License
1.03k stars 59 forks source link

Bojller is stripping away {} from variables #133

Closed trajche closed 3 years ago

trajche commented 4 years ago

We are using Bojler as a framework for some Marketo email templates. In Marketo you define various variables, such as background color with a placeholder such as: ${heroBackgroundColor}

After compile, this is stripped away to: $heroBackgroundColor

What we do currently is have a list of elements that we do a search & replace for, as the following example:

replace "$heroBackgroundColor"
with "${heroBackgroundColor}"

replace "$heroTwoBackgroundColor"
with "${heroTwoBackgroundColor}"

replace "$heroOneButtonBackgroundColor"
with "${heroOneButtonBackgroundColor}"

Is there any other, easier way of accomplishing this?

Hvala vam!

alenvuletic commented 4 years ago

Hi @trajche, we had same issue during Marketo implementation.

We did few adjustments on one specific project, maybe this will be useful for you:

const gulp = require( 'gulp' ),
        through = require( 'through2' ),
        sass = require( 'gulp-sass' ),
        gcmq = require( 'gulp-group-css-media-queries' ),
        gutil = require( 'gulp-util' ),
        juice = require( '@akzhan/gulp-juice' ),
        del = require( 'del' ),
        stripComments = require( 'gulp-strip-comments' ),
        connect = require( 'gulp-connect' ),
        path = require( 'path' ),
        filesToSass = [
            'source/sass/inlined.scss',
            'source/sass/embedded.scss',
        ],
        filesToWatch = [
            'source/sass/**/*.scss',
            'source/**/*.html',
        ];

// Ignore Marketo variables
if ( ! juice.codeBlocks ) {
    juice.codeBlocks = {};
}

juice.codeBlocks.mkto = {
    start: '${',
    end: '}',
};

// Build SASS
gulp.task( 'build:sass', function( done ) {
    'use strict';

    return gulp.src( filesToSass )
        .pipe(
            sass( {
                outputStyle: 'compressed',
            } )
            .on( 'error', gutil.log )
        )
        .pipe( gcmq() )
        .pipe( gulp.dest( 'public/css/' ) )
        .on( 'end', done );
} );

const replaceSpecials = function( file, enc, callback ) {
    'use strict';

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

    if ( file.isStream() ) {
        return callback( null, file );
    }

    if ( file.isBuffer() ) {
        let content = file.contents.toString();

        content = content.replace( /\#curlyBracketOpen\#/g, '{' );
        content = content.replace( /\#curlyBracketClose\#/g, '}' );

        file.contents = new Buffer( content );
        this.push( file );
    }

    callback();
};

// Inline CSS
gulp.task( 'inline:css', function( done ) {
    'use strict';

    return gulp.src( 'source/**/*.html' )
        .pipe(
            juice( {
                applyHeightAttributes: false,
                applyWidthAttributes: false,
                webResources: {
                    relativeTo: path.resolve( __dirname, 'public/' ),
                    images: false,
                    svgs: false,
                    scripts: false,
                    links: false,
                },
            } )
            .on( 'error', gutil.log )
        )
        .pipe( through.obj( replaceSpecials ) )
        .pipe( gulp.dest( 'public/' ) )
        .on( 'end', done );
} );

// Clean CSS
gulp.task( 'clean:css', function( done ) {
    'use strict';

    return del( [
        'public/css/',
    ] )
    .then( function() {
        done();
    } );
} );

// Clean HTML
gulp.task( 'clean:html', function( done ) {
    'use strict';

    return gulp.src( 'public/**/*.html' )
        .pipe(
            stripComments( {
                safe: true,
                trim: true,
            } )
            .on( 'error', gutil.log )
        )
        .pipe( gulp.dest( 'public/' ) )
        .pipe( connect.reload() )
        .on( 'end', done );
} );

// Default (Build)
gulp.task(
    'default',
    gulp.series( [
        'build:sass',
        'inline:css',
        'clean:css',
        'clean:html',
    ] )
);

// Start server w/ live reload
gulp.task( 'start', function( done ) {
    'use strict';

    connect.server( {
        port: 8000,
        root: 'public',
        livereload: true,
    } );

    done();
} );

// Watch
gulp.task( 'watch', function( done ) {
    'use strict';

    gulp.watch(
        filesToWatch,
        gulp.series( [
            'default',
        ] )
    );

    done();
} );

// Development mode
gulp.task(
    'dev',
    gulp.series( [
        'default',
        gulp.parallel( [
            'start',
            'watch',
        ] )
    ] )
);

// Clean project folder
gulp.task( 'clean', function( done ) {
    'use strict';

    return del( [
        'public/*',
        '!public/assets',
    ] )
    .then( function() {
        done();
    } );
} );

Let me know if you need help with it :)

trajche commented 4 years ago

Many thanks Alen. Will test this and come back to you later today!

trajche commented 4 years ago

@alenvuletic I managed to get it working by using the replaceSpecials and using #curlyBracketOpen# and #curlyBracketClose# but I am unable to define codeBlocks on juice.

I tried to add it as an option in html.js:

function inline() {
    return gulp.src( config.paths.html.inline.src )
        .pipe(
            juice( {
                applyHeightAttributes: false,
                applyWidthAttributesa: false,
                xmlMode: true,
                webResources: {
                    relativeTo: './dist',
                    images: false,
                    svgs: false,
                    scripts: false,
                    links: false,
                },
                codeBlocks: {
                    start: '${',
                    end: '}'
                },
            })
        )
        .pipe( through.obj( replaceSpecials ) )
        .pipe( gulp.dest( config.paths.html.inline.dest ) );
}

But did not succeed. Any tips on how to use it with the current gulpfile (the one you shared seems like from an earlier Bojler version)?

trajche commented 4 years ago

Since I am not sure how to set Juice global settings, current hack for anyone reading this:

Add two functions, replaceSpecials which is ran before the inline-ing by Juice and then replaceSpecialsAgain which is ran after the inline-ing and removal of Marketo tags.

const replaceSpecials = function( file, enc, callback ) {
            'use strict';

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

            if ( file.isStream() ) {
                return callback( null, file );
            }

            if ( file.isBuffer() ) {
                let content = file.contents.toString();

                content = content.replace( /\${/g, '#curlyBracketOpen#' );
                content = content.replace( /}/g, '#curlyBracketClose#' );

                file.contents = new Buffer.from( content );
                this.push( file );
    }

    callback();
};

const replaceSpecialsAgain = function( file, enc, callback ) {
    'use strict';

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

    if ( file.isStream() ) {
        return callback( null, file );
    }

    if ( file.isBuffer() ) {
        let content = file.contents.toString();
        content = content.replace( /\#curlyBracketOpen\#/g, '${' );
        content = content.replace( /\#curlyBracketClose\#/g, '}' );
        file.contents = new Buffer.from( content );
        this.push( file );
    }

    callback();
};

Then in html.js replace the inline() function to:

function inline() {
    return gulp.src( config.paths.html.inline.src )
        .pipe( through.obj( replaceSpecials ) )
        .pipe(
            juice( {
                applyHeightAttributes: false,
                applyWidthAttributesa: false,
                xmlMode: true,
                webResources: {
                    relativeTo: './dist',
                    images: false,
                    svgs: false,
                    scripts: false,
                    links: false,
                },
            })
        )
        .pipe( through.obj( replaceSpecialsAgain ) )
        .pipe( gulp.dest( config.paths.html.inline.dest ) );

}

If anyone figures out how to use codeBlocks please let me know :)

alenvuletic commented 3 years ago

Thanks @trajche for your comments!

We decided that we don't want to implement the solution to the project because we're trying to keep it simple and clean.

This is something that can be added per project by developers if they need it. It's very specific.

Once again, thanks for your time and comments!