Skip to content

Instantly share code, notes, and snippets.

@nelsonvassalo
Last active February 13, 2018 11:31
Show Gist options
  • Save nelsonvassalo/75547d960a9d24fbca8227bd5fa86625 to your computer and use it in GitHub Desktop.
Save nelsonvassalo/75547d960a9d24fbca8227bd5fa86625 to your computer and use it in GitHub Desktop.
Starter files for a Shopify workflow using gulp-shopify-theme based on example Gulpfile from @tmslnz
const argv = require('yargs').argv;
const gulp = require( 'gulp' );
const sass = require( 'gulp-sass' );
const changed = require( 'gulp-changed' );
const sourcemaps = require( 'gulp-sourcemaps' );
const uglify = require( 'gulp-uglify' );
const concat = require( 'gulp-concat' );
const replace = require( 'gulp-replace' );
const plumber = require( 'gulp-plumber' );
const notify = require('gulp-notify');
const gutil = require('gulp-util');
const browsersync = require( 'browser-sync' ).create();
const nano = require('cssnano');
const gulpif = require( 'gulp-if' );
const del = require( 'del' );
const addsrc = require( 'gulp-add-src' );
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const rename = require( 'gulp-rename' );
const yaml = require( 'gulp-yaml' );
const jsyaml = require( 'js-yaml' );
const theme = require( 'gulp-shopify-theme' ).create();
const shopifyconfig = require( './~shopifyconfig.json' );
var processors = [
autoprefixer({browsers: ['last 2 versions', 'ie >= 11']}), nano()];
var DESTINATION = argv.dest || 'dist';
var USE_JS_UGLIFY = !!(argv.uglify || process.env.USE_JS_UGLIFY);
var USE_SOURCEMAPS = true;
var USE_BROWSER_SYNC = true;
var BROWSER_SYNC_PORT = parseInt(argv.browsersync) || parseInt(argv.bs) || parseInt(process.env.BROWSER_SYNC_PORT) || '3000';
const sourceMappingURLCSSregExp = new RegExp('(.*?[/*]{2,}# sourceMappingURL=)(.*?)([/*]{2})', 'g');
const sourceMappingURLJSregExp = new RegExp('(.*?[/*]{2,}# sourceMappingURL=)(.*?)', 'g');
const sourceMappingURLCSSreplace = '{% raw %}$1{% endraw %}$2{% raw %}$3{% endraw %}';
const sourceMappingURLJSreplace = '{% raw %}$1{% endraw %}$2';
shopifyconfig.root = process.cwd() + '/' + DESTINATION;
gulp.task( 'default', [ 'css', 'js', 'js-libs', 'fonts', 'images', 'copy', 'configs' ] );
gulp.task( 'dev', [ 'theme', 'default', 'browsersync', 'watch' ] );
gulp.task( 'clean', function () {
return del(DESTINATION);
});
gulp.task( 'purge', [ 'theme' ], function (done) {
theme.purge();
done();
});
gulp.task( 'theme', function () {
theme.init( shopifyconfig );
});
gulp.task( 'watch', function () {
USE_JS_UGLIFY = false;
// Watch & run tasks
gulp.watch( 'src/styles/**/*.{scss,liquid}', [ 'reload-on-css' ] );
gulp.watch( 'src/scripts/theme.js', [ 'reload-on-js' ] );
gulp.watch( ['src/scripts/vendor.js', 'src/scripts/vendor/*.js'], [ 'reload-on-js-libs' ] );
gulp.watch( 'src/assets/fonts/**/*', [ 'reload-on-fonts' ] );
gulp.watch( 'src/assets/images/**/*', [ 'reload-on-images' ] );
gulp.watch( 'src/{layout,config,snippets,sections,templates,locales}/**/*', [ 'reload-on-copy' ]);
});
gulp.task( 'css',function () {
return gulp.src( 'src/styles/theme.scss')
.pipe( plumber({
errorHandler: (error) => {
notify.onError({
title: "Gulp error in " + error.plugin,
message: JSON.parse(error.toString())
})(error);
// play a sound once
gutil.beep(2);
}}))
.pipe( sourcemaps.init() )
.pipe( sass())
.pipe( replace( /({{|}}|{%|%})/g, '/*!$1*/' ) ) // Comment out Liquid tags, so post-css doesn't trip out
.pipe( postcss( [
autoprefixer({browsers: [ 'last 2 versions', 'Explorer >= 11' ]}),
] ) )
.pipe( replace( /\/\*!({{|}}|{%|%})\*\//g, '$1' ) ) // Re-enable Liquid tags
.pipe( rename( 'main.css' ) )
.pipe( sourcemaps.write()) // css_all.css.map
// .pipe( rename(appendLiquidExt)) // css_all.css.liquid
// .pipe( replace( sourceMappingURLCSSregExp, sourceMappingURLCSSreplace ) )
.pipe( gulp.dest( DESTINATION + '/assets' ) )
.pipe( theme.stream() );
});
gulp.task( 'js', () => {
return gulp.src( 'src/scripts/theme.js' )
.pipe( plumber({
errorHandler: (error) => {
notify.onError({
title: "Gulp error in " + error.plugin,
message: error.toString()
})(error);
// play a sound once
gutil.beep(2);
}}))
.pipe( sourcemaps.init() )
// .pipe( babel({presets: ['env']}) )
.pipe( concat( 'main.js' ) )
.pipe( gulpif( USE_JS_UGLIFY, uglify() ) )
.pipe( sourcemaps.write())
//.pipe( rename(appendLiquidExt))
//.pipe( replace( sourceMappingURLJSregExp, sourceMappingURLJSreplace ) )
.pipe( gulp.dest( DESTINATION + '/assets' ) )
.pipe( theme.stream() );
});
gulp.task( 'js-libs', () => {
return gulp.src( ['src/scripts/vendor/*.js', 'src/scripts/vendor.js'] )
.pipe( plumber({
errorHandler: (error) => {
notify.onError({
title: "Gulp error in " + error.plugin,
message: error.toString()
})(error);
// play a sound once
gutil.beep(2);
}}) )
.pipe( sourcemaps.init())
.pipe( concat( 'libs.js' ) )
.pipe( gulpif( USE_JS_UGLIFY, uglify() ) )
.pipe( sourcemaps.write())
.pipe( gulp.dest( DESTINATION + '/assets' ) )
.pipe( theme.stream() );
});
gulp.task( 'fonts', () => {
return gulp.src( [ 'src/assets/fonts/**/*.{ttf,woff,woff2,eof,eot,otf,svg}' ] )
.pipe( plumber({
errorHandler: (error) => {
notify.onError({
title: "Gulp error in " + error.plugin,
message: error.toString()
})(error);
// play a sound once
gutil.beep(2);
}}) )
.pipe( changed( DESTINATION ) )
.pipe( rename( flatten ))
.pipe( rename({ dirname: '', prefix: 'fonts_' }))
.pipe( gulp.dest( DESTINATION + '/assets' ) )
.pipe( theme.stream() );
});
gulp.task( 'images', () => {
return gulp.src( [ 'src/assets/images/**/*.{svg,png,jpg,jpeg,gif,ico}', '!src/assets/images/src/**/*' ] )
.pipe( plumber({
errorHandler: (error) => {
notify.onError({
title: "Gulp error in " + error.plugin,
message: error.toString()
})(error);
// play a sound once
gutil.beep(2);
}}) )
.pipe( changed( DESTINATION ) )
.pipe( rename( flatten ))
.pipe( rename({ dirname: '', prefix: 'images_' }))
.pipe( gulp.dest( DESTINATION + '/assets' ) )
.pipe( theme.stream() );
});
gulp.task( 'copy', () => {
return gulp.src( [ 'src/{layout,snippets,templates,sections}/**/*.liquid' ] )
.pipe( plumber({
errorHandler: (error) => {
notify.onError({
title: "Gulp error in " + error.plugin,
message: JSON.stringify(error)
})(error);
// play a sound once
gutil.beep(2);
}}) )
.pipe( replace( /{% schema %}([^]*.+[^]*){% endschema %}/gi, replaceYAMLwithJSON ) )
.pipe( replace(/({%)(?!\s*?(?:end)?(?:raw|schema|javascript|stylesheet)\s*?)(.+?)(%})/g, '$1- $2 -$3') ) // make whitespace-insensitive tags {% -> {%-
.pipe( replace( /^\s*[\r\n]/gm, '' ) ) // remove empty lines
.pipe( changed( DESTINATION))
.pipe( gulp.dest( DESTINATION) )
.pipe( theme.stream() );
});
gulp.task( 'configs', () => {
return gulp.src( [ 'src/{config,locales}/**/*.*' ] )
.pipe( plumber({
errorHandler: (error) => {
notify.onError({
title: "Gulp error in " + error.plugin,
message: error.toString()
})(error);
// play a sound once
gutil.beep(2);
}}) )
.pipe( yaml({space: 2}) )
.pipe( changed( DESTINATION) )
.pipe( gulp.dest( DESTINATION ) )
.pipe( theme.stream() );
});
gulp.task('reload-on-css', ['css'], reload);
gulp.task('reload-on-js', ['js'], reload);
gulp.task('reload-on-js-libs', ['js-libs'], reload);
gulp.task('reload-on-fonts', ['fonts'], reload);
gulp.task('reload-on-images', ['images'], reload);
gulp.task('reload-on-copy', ['copy', 'configs'], reload);
function reload (done) {
if (!USE_BROWSER_SYNC) return done();
browsersync.reload(); done();
}
gulp.task( 'browsersync', function (done) {
if (!USE_BROWSER_SYNC) return done();
browsersync.init({
port: BROWSER_SYNC_PORT, ui: { port: +BROWSER_SYNC_PORT + 1 },
proxy: 'https://'+ shopifyconfig.shop_name +'.myshopify.com',
browser: [],
notify: true,
startPath: "/?preview_theme_id=" + shopifyconfig.theme_id,
}, done);
});
console.log('DESTINATION', DESTINATION);
console.log('USE_JS_UGLIFY', USE_JS_UGLIFY);
console.log('USE_SOURCEMAPS', USE_SOURCEMAPS);
console.log('USE_BROWSER_SYNC', USE_BROWSER_SYNC);
console.log('BROWSER_SYNC_PORT', BROWSER_SYNC_PORT);
function replaceYAMLwithJSON (match, g1) {
if (match) {
var yamlString = g1.replace(/{% (end)?schema %}/, '');
var parsedYaml = jsyaml.safeLoad(yamlString);
var jsonString = JSON.stringify(parsedYaml, null, ' ');
return '{% schema %}\n' + jsonString + '\n{% endschema %}';
}
}
function makeLiquidSourceMappingURL (file) {
return "main.css.map";
}
function appendLiquidExt (path) {
if (path.extname === '.map') return;
// if (path.extname === '.css') {
// path.extname = '.scss';
// }
path.basename += path.extname;
path.extname = '.liquid';
}
function flatten (path) {
if (path.dirname !== '.') {
path.basename = path.dirname.replace('/', '_') + '_' + path.basename;
}
}
@charset "UTF-8";
/*============================================================================
[replace with theme name] | Built with Slate
- You cannot use native CSS/Sass @imports in this file without a build script
==============================================================================*/
/*================ UTILS ================*/
@import 'tools/mixins.scss';
/*================ SETTINGS ================*/
@import 'settings/variables.scss';
/*================ COMMON ================*/
@import 'global/normalize.scss';
@import 'global/slate-reset.scss';
@import 'global/blank-states.scss';
@import 'global/fonts.scss';
@import 'global/helper-classes.scss';
@import 'global/grid.scss';
@import 'global/layout.scss';
@import 'global/icons.scss';
@import 'global/rte.scss';
@import 'global/responsive-tables.scss';
@import 'global/links-buttons.scss';
@import 'global/forms.scss';
@import 'global/typography.scss';
/*================ MODULES ================*/
@import 'modules/site-header.scss';
@import 'modules/site-footer.scss';
@import 'modules/gift-card-template.scss';
/*================ PAGES ================*/
@import 'pages/home.scss';
// my first custom page
@import 'pages/edition.scss';
<!doctype html>
<!--[if IE 9]> <html class="ie9 no-js supports-no-cookies" lang="{{ shop.locale }}"> <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--> <html class="no-js supports-no-cookies" lang="{{ shop.locale }}"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="theme-color" content="{{ settings.color_primary }}">
<link rel="canonical" href="{{ canonical_url }}">
{% if settings.favicon != blank %}
<link rel="shortcut icon" href="{{ settings.favicon | img_url: '32x32' }}" type="image/png">
{% endif %}
{% capture seo_title %}
{{ page_title }}
{% if current_tags %}
{%- assign meta_tags = current_tags | join: ', ' %} &ndash; {{ 'general.meta.tags' | t: tags: meta_tags -}}
{% endif %}
{% if current_page != 1 %}
&ndash; {{ 'general.meta.page' | t: page: current_page }}
{% endif %}
{% unless page_title contains shop.name %}
&ndash; {{ shop.name }}
{% endunless %}
{% endcapture %}
<title>{{ seo_title }}</title>
{% if page_description %}
<meta name="description" content="{{ page_description | escape }}">
{% endif %}
{% include 'social-meta-tags' %}
{{ 'main.scss.liquid' | asset_url | stylesheet_tag }}
<script>
document.documentElement.className = document.documentElement.className.replace('no-js', 'js');
window.theme = {
strings: {
addToCart: {{ 'products.product.add_to_cart' | t | json }},
soldOut: {{ 'products.product.sold_out' | t | json }},
unavailable: {{ 'products.product.unavailable' | t | json }}
},
moneyFormat: {{ shop.money_format | json }}
};
</script>
{% if template.directory == 'customers' %}
<!--[if (gt IE 9)|!(IE)]><!--><script src="{{ 'shopify_common.js' | shopify_asset_url }}" defer="defer"></script><!--<![endif]-->
<!--[if lte IE 9]><script src="{{ 'shopify_common.js' | shopify_asset_url }}"></script><![endif]-->
{% endif %}
<!--[if (gt IE 9)|!(IE)]><!--><script src="{{ 'libs.js' | asset_url }}" defer="defer"></script><!--<![endif]-->
<!--[if lt IE 9]><script src="{{ 'libs.js' | asset_url }}"></script><![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--><script src="{{ 'main.js' | asset_url }}" defer="defer"></script><!--<![endif]-->
<!--[if lt IE 9]><script src="{{ 'main.js' | asset_url }}"></script><![endif]-->
{{ content_for_header }}
</head>
<body id="{{ page_title | handle }}" class="template-{{ template.name | handle }}">
<a class="in-page-link visually-hidden skip-link" href="#MainContent">{{ 'general.accessibility.skip_to_content' | t }}</a>
{% section 'header' %}
<main role="main" id="MainContent" >
{% if page.handle == '/' %}
//page
{{ content_for_index }}
{% else %}
//layout
{{ content_for_layout}}
{% endif %}
</main>
{% section 'footer' %}
</body>
</html>
@tmslnz
Copy link

tmslnz commented Feb 7, 2018

Are you sure it's a Gulp problem?
Is the CSS file being generated in your DESTINATION dir?
Check your theme HTML. Mine has: <link rel="stylesheet" type="text/css" href="{{ 'css_all.scss.css' | asset_url }}"/>
Is the theme.liquid up at Shopify the same you have in your dist? Has it been uploaded? Does it have the correct paths?

@nelsonvassalo
Copy link
Author

nelsonvassalo commented Feb 8, 2018

@tmslnz It's working now. Somehow the connection wasn't being properly set with the Shopify theme (wrong id maybe). I kept having problems with the location and writing of the path of the map files, so I took that out am in instead printing them directly on each file as base64 and it works. Thanks!

@nelsonvassalo
Copy link
Author

@tmslnz Any experience using this to working in a team with versioning? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment