diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000000..3c078e9f99 --- /dev/null +++ b/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "es2015" + ] +} diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 69fad35801..0000000000 --- a/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "bower_components" -} diff --git a/.eslintrc b/.eslintrc index 95a8def2e9..30a5994f7a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -10,6 +10,7 @@ "node": true, "amd": true }, + "parser": "babel-eslint", "rules": { "no-console": 0 } diff --git a/assets/manifest.json b/assets/manifest.json deleted file mode 100644 index aca495c846..0000000000 --- a/assets/manifest.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "dependencies": { - "main.js": { - "files": [ - "scripts/main.js" - ], - "main": true - }, - "main.css": { - "files": [ - "styles/main.scss" - ], - "main": true - }, - "customizer.js": { - "files": [ - "scripts/customizer.js" - ] - }, - "jquery.js": { - "bower": ["jquery"] - } - }, - "config": { - "devUrl": "http://example.dev" - } -} diff --git a/assets/scripts/main.js b/assets/scripts/main.js index 53062de700..1039fa2603 100644 --- a/assets/scripts/main.js +++ b/assets/scripts/main.js @@ -1,77 +1,51 @@ -/* ======================================================================== - * DOM-based Routing - * Based on http://goo.gl/EUTi53 by Paul Irish - * - * Only fires on body classes that match. If a body class contains a dash, - * replace the dash with an underscore when adding it to the object below. - * - * .noConflict() - * The routing is enclosed within an anonymous function so that you can - * always reference jQuery with $, even when in .noConflict() mode. - * ======================================================================== */ - -(function($) { - - // Use this variable to set up the common and page specific functions. If you - // rename this variable, you will also need to rename the namespace below. - var Sage = { - // All pages - 'common': { - init: function() { - // JavaScript to be fired on all pages - }, - finalize: function() { - // JavaScript to be fired on all pages, after page specific JS is fired - } - }, - // Home page - 'home': { - init: function() { - // JavaScript to be fired on the home page - }, - finalize: function() { - // JavaScript to be fired on the home page, after the init JS - } +import "../styles/main.scss"; + +import $ from 'jquery'; +import Router from './util/router'; + +// Import Bootstrap +import "bootstrap/dist/js/umd/util.js"; +import "bootstrap/dist/js/umd/alert.js"; +import "bootstrap/dist/js/umd/button.js"; +import "bootstrap/dist/js/umd/carousel.js"; +import "bootstrap/dist/js/umd/collapse.js"; +import "bootstrap/dist/js/umd/dropdown.js"; +import "bootstrap/dist/js/umd/modal.js"; +import "bootstrap/dist/js/umd/scrollspy.js"; +import "bootstrap/dist/js/umd/tab.js"; +import "bootstrap/dist/js/umd/tooltip.js"; +import "bootstrap/dist/js/umd/popover.js"; + +// Use this variable to set up the common and page specific functions. If you +// rename this variable, you will also need to rename the namespace below. +var Sage = { + // All pages + 'common': { + init: function() { + // JavaScript to be fired on all pages }, - // About us page, note the change from about-us to about_us. - 'about_us': { - init: function() { - // JavaScript to be fired on the about us page - } + finalize: function() { + // JavaScript to be fired on all pages, after page specific JS is fired } - }; - - // The routing fires all common scripts, followed by the page specific scripts. - // Add additional events for more control over timing e.g. a finalize event - var UTIL = { - fire: function(func, funcname, args) { - var fire; - var namespace = Sage; - funcname = (funcname === undefined) ? 'init' : funcname; - fire = func !== ''; - fire = fire && namespace[func]; - fire = fire && typeof namespace[func][funcname] === 'function'; - - if (fire) { - namespace[func][funcname](args); - } + }, + // Home page + 'home': { + init: function() { + // JavaScript to be fired on the home page }, - loadEvents: function() { - // Fire common init JS - UTIL.fire('common'); - - // Fire page-specific init JS, and then finalize JS - $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) { - UTIL.fire(classnm); - UTIL.fire(classnm, 'finalize'); - }); - - // Fire common finalize JS - UTIL.fire('common', 'finalize'); + finalize: function() { + // JavaScript to be fired on the home page, after the init JS } - }; - - // Load Events - $(document).ready(UTIL.loadEvents); + }, + // About us page, note the change from about-us to about_us. + 'about_us': { + init: function() { + // JavaScript to be fired on the about us page + } + } +}; -})(jQuery); // Fully reference jQuery after this point. +// Load Events +$(document).ready(function () { + new Router(Sage).loadEvents(); +}); diff --git a/assets/scripts/util/router.js b/assets/scripts/util/router.js new file mode 100644 index 0000000000..ca9694ecc5 --- /dev/null +++ b/assets/scripts/util/router.js @@ -0,0 +1,45 @@ +import $ from 'jquery'; + +/* ======================================================================== + * DOM-based Routing + * Based on http://goo.gl/EUTi53 by Paul Irish + * + * Only fires on body classes that match. If a body class contains a dash, + * replace the dash with an underscore when adding it to the object below. + * ======================================================================== */ + +// The routing fires all common scripts, followed by the page specific scripts. +// Add additional events for more control over timing e.g. a finalize event +export default class Router { + constructor(namespace) { + this.namespace = namespace; + } + + fire(func, funcname, args) { + funcname = (funcname === undefined) ? 'init' : funcname; + let fire = func !== ''; + fire = fire && this.namespace[func]; + fire = fire && typeof this.namespace[func][funcname] === 'function'; + + if (fire) { + this.namespace[func][funcname](args); + } + } + + loadEvents() { + // Fire common init JS + this.fire('common'); + + // Fire page-specific init JS, and then finalize JS + $.each( + document.body.className.replace(/-/g, '_').split(/\s+/), + (i, className) => { + this.fire(className); + this.fire(className, 'finalize'); + } + ); + + // Fire common finalize JS + this.fire('common', 'finalize'); + } +} diff --git a/assets/styles/components/_grid.scss b/assets/styles/components/_grid.scss index 77c019e873..fb3e829a3c 100644 --- a/assets/styles/components/_grid.scss +++ b/assets/styles/components/_grid.scss @@ -1,15 +1,18 @@ // Grid system .main { - @include make-col($main-sm-columns, $main-sm-columns, $grid-gutter-width); + @include make-col(); @include media-breakpoint-up(sm) { + @include make-col-span($main-sm-columns); .sidebar-primary & { - @include make-col($main-sm-columns - $sidebar-sm-columns, $main-sm-columns, $grid-gutter-width); + @include make-col-span($main-sm-columns - $sidebar-sm-columns); } } } .sidebar { + @include make-col(); + @include media-breakpoint-up(sm) { - @include make-col($sidebar-sm-columns, $main-sm-columns, $grid-gutter-width); + @include make-col-span($sidebar-sm-columns); } } diff --git a/assets/styles/main.scss b/assets/styles/main.scss index 7ae1198a85..e91ca6fdd4 100644 --- a/assets/styles/main.scss +++ b/assets/styles/main.scss @@ -1,9 +1,7 @@ @import "common/variables"; -// Automatically injected Bower dependencies via wiredep (never manually edit this block) -// bower:scss -@import "../../bower_components/bootstrap/scss/bootstrap.scss"; -// endbower +// Import Boostrap from node_modules/... +@import "~bootstrap/scss/bootstrap"; @import "common/global"; @import "components/buttons"; diff --git a/bower.json b/bower.json deleted file mode 100644 index 6f90838f7b..0000000000 --- a/bower.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "sage", - "homepage": "https://roots.io/sage/", - "authors": [ - "Roots " - ], - "license": "MIT", - "private": true, - "dependencies": { - "bootstrap": "git://github.com/twbs/bootstrap.git#v4-dev", - "tether": "^1.1.1" - } -} diff --git a/dev.js b/dev.js new file mode 100644 index 0000000000..8a473b918f --- /dev/null +++ b/dev.js @@ -0,0 +1,30 @@ +/* eslint no-console: 0 */ + +var webpack = require('webpack'), + webpackDevMiddleware = require('webpack-dev-middleware'), + webpackHotMiddleware = require('webpack-hot-middleware'), + browserSync = require('browser-sync'); + +var devBuildConfig = require('./webpack.config'), + compiler = webpack(devBuildConfig); + +browserSync.init({ + proxy: { + target: 'http://example.dev', // change to dev server + middleware: [ + webpackDevMiddleware(compiler, { + publicPath: devBuildConfig.output.publicPath, + stats: { + colors: true + }, + }), + webpackHotMiddleware(compiler, { + log: browserSync.notify + }) + ] + }, + files: [ + 'templates/**/*.php', + 'src/**/*.php' + ] +}); diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 6c6874a1be..0000000000 --- a/gulpfile.js +++ /dev/null @@ -1,288 +0,0 @@ -// ## Globals -var argv = require('minimist')(process.argv.slice(2)); -var autoprefixer = require('gulp-autoprefixer'); -var browserSync = require('browser-sync').create(); -var changed = require('gulp-changed'); -var concat = require('gulp-concat'); -var flatten = require('gulp-flatten'); -var gulp = require('gulp'); -var gulpif = require('gulp-if'); -var imagemin = require('gulp-imagemin'); -var eslint = require('gulp-eslint'); -var lazypipe = require('lazypipe'); -var less = require('gulp-less'); -var merge = require('merge-stream'); -var cssNano = require('gulp-cssnano'); -var plumber = require('gulp-plumber'); -var rev = require('gulp-rev'); -var runSequence = require('run-sequence'); -var sass = require('gulp-sass'); -var sourcemaps = require('gulp-sourcemaps'); -var uglify = require('gulp-uglify'); - -// See https://github.com/austinpray/asset-builder -var manifest = require('asset-builder')('./assets/manifest.json'); - -// `path` - Paths to base asset directories. With trailing slashes. -// - `path.source` - Path to the source files. Default: `assets/` -// - `path.dist` - Path to the build directory. Default: `dist/` -var path = manifest.paths; - -// `config` - Store arbitrary configuration values here. -var config = manifest.config || {}; - -// `globs` - These ultimately end up in their respective `gulp.src`. -// - `globs.js` - Array of asset-builder JS dependency objects. Example: -// ``` -// {type: 'js', name: 'main.js', globs: []} -// ``` -// - `globs.css` - Array of asset-builder CSS dependency objects. Example: -// ``` -// {type: 'css', name: 'main.css', globs: []} -// ``` -// - `globs.fonts` - Array of font path globs. -// - `globs.images` - Array of image path globs. -// - `globs.bower` - Array of all the main Bower files. -var globs = manifest.globs; - -// `project` - paths to first-party assets. -// - `project.js` - Array of first-party JS assets. -// - `project.css` - Array of first-party CSS assets. -var project = manifest.getProjectGlobs(); - -// CLI options -var enabled = { - // Enable static asset revisioning when `--production` - rev: argv.production, - // Disable source maps when `--production` - maps: !argv.production, - // Fail styles task on error when `--production` - failStyleTask: argv.production, - // Fail due to ESLint warnings only when `--production` - failESLint: argv.production, - // Strip debug statments from javascript when `--production` - stripJSDebug: argv.production -}; - -// Path to the compiled assets manifest in the dist directory -var revManifest = path.dist + 'assets.json'; - -// ## Reusable Pipelines -// See https://github.com/OverZealous/lazypipe - -// ### CSS processing pipeline -// Example -// ``` -// gulp.src(cssFiles) -// .pipe(cssTasks('main.css') -// .pipe(gulp.dest(path.dist + 'styles')) -// ``` -var cssTasks = function(filename) { - return lazypipe() - .pipe(function() { - return gulpif(!enabled.failStyleTask, plumber()); - }) - .pipe(function() { - return gulpif(enabled.maps, sourcemaps.init()); - }) - .pipe(function() { - return gulpif('*.less', less()); - }) - .pipe(function() { - return gulpif('*.scss', sass({ - outputStyle: 'nested', // libsass doesn't support expanded yet - precision: 10, - includePaths: ['.'], - errLogToConsole: !enabled.failStyleTask - })); - }) - .pipe(concat, filename) - .pipe(autoprefixer, { - browsers: [ - 'last 2 versions', - 'android 4', - 'opera 12' - ] - }) - .pipe(cssNano, { - safe: true - }) - .pipe(function() { - return gulpif(enabled.rev, rev()); - }) - .pipe(function() { - return gulpif(enabled.maps, sourcemaps.write('.', { - sourceRoot: 'assets/styles/' - })); - })(); -}; - -// ### JS processing pipeline -// Example -// ``` -// gulp.src(jsFiles) -// .pipe(jsTasks('main.js') -// .pipe(gulp.dest(path.dist + 'scripts')) -// ``` -var jsTasks = function(filename) { - return lazypipe() - .pipe(function() { - return gulpif(enabled.maps, sourcemaps.init()); - }) - .pipe(concat, filename) - .pipe(uglify, { - compress: { - 'drop_debugger': enabled.stripJSDebug - } - }) - .pipe(function() { - return gulpif(enabled.rev, rev()); - }) - .pipe(function() { - return gulpif(enabled.maps, sourcemaps.write('.', { - sourceRoot: 'assets/scripts/' - })); - })(); -}; - -// ### Write to rev manifest -// If there are any revved files then write them to the rev manifest. -// See https://github.com/sindresorhus/gulp-rev -var writeToManifest = function(directory) { - return lazypipe() - .pipe(gulp.dest, path.dist + directory) - .pipe(browserSync.stream, {match: '**/*.{js,css}'}) - .pipe(rev.manifest, revManifest, { - base: path.dist, - merge: true - }) - .pipe(gulp.dest, path.dist)(); -}; - -// ## Gulp tasks -// Run `gulp -T` for a task summary - -// ### Styles -// `gulp styles` - Compiles, combines, and optimizes Bower CSS and project CSS. -// By default this task will only log a warning if a precompiler error is -// raised. If the `--production` flag is set: this task will fail outright. -gulp.task('styles', ['wiredep'], function() { - var merged = merge(); - manifest.forEachDependency('css', function(dep) { - var cssTasksInstance = cssTasks(dep.name); - if (!enabled.failStyleTask) { - cssTasksInstance.on('error', function(err) { - console.error(err.message); - this.emit('end'); - }); - } - merged.add(gulp.src(dep.globs, {base: 'styles'}) - .pipe(cssTasksInstance)); - }); - return merged - .pipe(writeToManifest('styles')); -}); - -// ### Scripts -// `gulp scripts` - Runs ESLint then compiles, combines, and optimizes Bower JS -// and project JS. -gulp.task('scripts', ['lint'], function() { - var merged = merge(); - manifest.forEachDependency('js', function(dep) { - merged.add( - gulp.src(dep.globs, {base: 'scripts'}) - .pipe(jsTasks(dep.name)) - ); - }); - return merged - .pipe(writeToManifest('scripts')); -}); - -// ### Fonts -// `gulp fonts` - Grabs all the fonts and outputs them in a flattened directory -// structure. See: https://github.com/armed/gulp-flatten -gulp.task('fonts', function() { - return gulp.src(globs.fonts) - .pipe(flatten()) - .pipe(gulp.dest(path.dist + 'fonts')) - .pipe(browserSync.stream()); -}); - -// ### Images -// `gulp images` - Run lossless compression on all the images. -gulp.task('images', function() { - return gulp.src(globs.images) - .pipe(imagemin({ - progressive: true, - interlaced: true, - svgoPlugins: [{removeUnknownsAndDefaults: false}, {cleanupIDs: false}] - })) - .pipe(gulp.dest(path.dist + 'images')) - .pipe(browserSync.stream()); -}); - -// ### ESLint -// `gulp lint` - Lints configuration JSON and project JS. -gulp.task('lint', function() { - return gulp.src([ - 'gulpfile.js' - ].concat(project.js)) - .pipe(eslint()) - .pipe(eslint.format()) - .pipe(gulpif(enabled.failESLint, eslint.failAfterError())); -}); - -// ### Clean -// `gulp clean` - Deletes the build folder entirely. -gulp.task('clean', require('del').bind(null, [path.dist])); - -// ### Watch -// `gulp watch` - Use BrowserSync to proxy your dev server and synchronize code -// changes across devices. Specify the hostname of your dev server at -// `manifest.config.devUrl`. When a modification is made to an asset, run the -// build step for that asset and inject the changes into the page. -// See: http://www.browsersync.io -gulp.task('watch', function() { - browserSync.init({ - files: ['{src,templates}/**/*.php'], - proxy: config.devUrl, - snippetOptions: { - whitelist: ['/wp-admin/admin-ajax.php'], - blacklist: ['/wp-admin/**'] - } - }); - gulp.watch([path.source + 'styles/**/*'], ['styles']); - gulp.watch([path.source + 'scripts/**/*'], ['lint', 'scripts']); - gulp.watch([path.source + 'fonts/**/*'], ['fonts']); - gulp.watch([path.source + 'images/**/*'], ['images']); - gulp.watch(['bower.json', 'assets/manifest.json'], ['build']); -}); - -// ### Build -// `gulp build` - Run all the build tasks but don't clean up beforehand. -// Generally you should be running `gulp` instead of `gulp build`. -gulp.task('build', function(callback) { - runSequence('styles', - 'scripts', - ['fonts', 'images'], - callback); -}); - -// ### Wiredep -// `gulp wiredep` - Automatically inject Less and Sass Bower dependencies. See -// https://github.com/taptapship/wiredep -gulp.task('wiredep', function() { - var wiredep = require('wiredep').stream; - return gulp.src(project.css) - .pipe(wiredep()) - .pipe(changed(path.source + 'styles', { - hasChanged: changed.compareSha1Digest - })) - .pipe(gulp.dest(path.source + 'styles')); -}); - -// ### Gulp -// `gulp` - Run a complete build. To compile for production run `gulp --production`. -gulp.task('default', ['clean'], function() { - gulp.start('build'); -}); diff --git a/package.json b/package.json index 02769e5ec7..1d471f4f96 100644 --- a/package.json +++ b/package.json @@ -18,45 +18,52 @@ } ], "scripts": { - "build": "bower install && gulp", - "lint": "gulp lint" + "build:production": "export SAGE_ENV=production && webpack", + "build": "export SAGE_ENV=development && webpack", + "watch": "export SAGE_ENV=development && node dev.js" }, "engines": { "node": ">= 0.12.0", "npm": ">=2.1.5" }, "devDependencies": { - "asset-builder": "^1.1.0", - "browser-sync": "^2.10.1", - "del": "^2.2.0", - "gulp": "^3.9.0", - "gulp-autoprefixer": "^3.1.0", - "gulp-changed": "^1.3.0", - "gulp-concat": "^2.6.0", - "gulp-cssnano": "^2.1.0", - "gulp-eslint": "^1.1.1", - "gulp-flatten": "0.2.0", - "gulp-if": "^2.0.0", - "gulp-imagemin": "^2.4.0", - "gulp-less": "^3.0.5", - "gulp-cssnano": "^2.1.0", - "gulp-eslint": "^1.1.1", - "gulp-flatten": "0.2.0", - "gulp-if": "^2.0.0", - "gulp-imagemin": "^2.4.0", - "gulp-less": "^3.0.5", - "gulp-plumber": "^1.0.1", - "gulp-rename": "^1.2.2", - "gulp-rev": "^6.0.1", - "gulp-sass": "^2.1.1", - "gulp-sourcemaps": "^1.6.0", - "gulp-uglify": "^1.5.1", + "assets-webpack-plugin": "^3.3.0", + "autoprefixer": "^6.1.0", + "babel-cli": "^6.1.18", + "babel-core": "^6.1.20", + "babel-eslint": "^5.0.0", + "babel-loader": "^6.1.0", + "babel-preset-es2015": "^6.1.18", + "babel-register": "^6.5.2", + "body-parser": "^1.14.1", + "browser-sync": "^2.11.1", + "clean-webpack-plugin": "^0.1.3", + "css-loader": "^0.22.0", + "cssnano": "^3.5.2", + "eslint": "^1.9.0", + "eslint-config-airbnb": "^1.0.0", + "eslint-loader": "^1.3.0", + "extract-text-webpack-plugin": "^0.9.1", + "file-loader": "^0.8.5", "imagemin-pngcrush": "^4.1.0", - "lazypipe": "^1.0.1", - "merge-stream": "^1.0.0", - "minimist": "^1.2.0", - "run-sequence": "^1.1.5", - "traverse": "^0.6.6", - "wiredep": "^3.0.0" + "imports-loader": "^0.6.5", + "monkey-hot-loader": "0.0.3", + "node-sass": "^3.4.2", + "optimize-css-assets-webpack-plugin": "^1.3.0", + "postcss": "^5.0.18", + "postcss-loader": "^0.8.0", + "resolve-url-loader": "^1.4.3", + "sass-loader": "^3.1.1", + "style-loader": "^0.13.0", + "url-loader": "^0.5.7", + "webpack": "^1.12.4", + "webpack-dev-middleware": "^1.2.0", + "webpack-hot-middleware": "^2.5.0" + }, + "dependencies": { + "babel-runtime": "^6.5.0", + "bootstrap": "github:twbs/bootstrap#v4.0.0-alpha.2", + "jquery": "^2.1.4", + "tether": "^1.2.0" } } diff --git a/src/admin.php b/src/admin.php index 863a6ced6d..0313e8cfaf 100644 --- a/src/admin.php +++ b/src/admin.php @@ -12,5 +12,5 @@ * Customizer JS */ add_action('customize_preview_init', function () { - wp_enqueue_script('sage/customizer.js', asset_path('scripts/customizer.js'), ['customize-preview'], null, true); + wp_enqueue_script('sage/customizer.js', asset_path('customizer.js'), ['customize-preview'], null, true); }); diff --git a/src/setup.php b/src/setup.php old mode 100644 new mode 100755 index 0d8c8f6e20..7f32f0cec4 --- a/src/setup.php +++ b/src/setup.php @@ -6,8 +6,8 @@ * Theme assets */ add_action('wp_enqueue_scripts', function () { - wp_enqueue_style('sage/main.css', asset_path('styles/main.css'), false, null); - wp_enqueue_script('sage/main.js', asset_path('scripts/main.js'), ['jquery'], null, true); + wp_enqueue_style('sage/main.css', asset_path('main.css'), false, null); + wp_enqueue_script('sage/main.js', asset_path('main.js'), ['jquery'], null, true); }, 100); /** @@ -62,7 +62,7 @@ * Use main stylesheet for visual editor * @see assets/styles/layouts/_tinymce.scss */ - add_editor_style(asset_path('styles/main.css')); + add_editor_style(asset_path('main.css')); }); /** diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000000..ef2b6fa1c6 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,142 @@ +var webpack = require('webpack'), + path = require('path'), + autoprefixer = require('autoprefixer'), + Clean = require("clean-webpack-plugin"), + AssetsPlugin = require('assets-webpack-plugin'), + ExtractTextPlugin = require('extract-text-webpack-plugin'), + OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'), + cssnano = require('cssnano'); + +var SAGE_ENV = process.env.SAGE_ENV || 'development', + webpackConfig; + +var sage = { + publicPath: '/app/themes/sage/dist/', + dist: path.join(__dirname, 'dist'), + manifest: 'assets.json', + // set to true to extract css in dev mode (prevents "hot" update) + extractStyles: false +}; + +// format output for Sage : { "name.ext": "hash.ext" } +var assetsPluginProcessOutput = function (assets) { + var results = {}, + name, + ext; + + for (name in assets) { + if (assets.hasOwnProperty(name)) { + for (ext in assets[name]) { + if (assets[name].hasOwnProperty(ext)) { + results[name + '.' + ext] = assets[name][ext]; + } + } + } + } + return JSON.stringify(results); +} + +webpackConfig = { + entry: { + main: [ + './assets/scripts/main' + ], + customizer: [ + './assets/scripts/customizer' + ] + }, + output: { + path: sage.dist, + publicPath: sage.publicPath + }, + module: { + preLoaders: [ + { + test: /\.jsx?$/, + exclude: /node_modules/, + loader: 'eslint' + } + ], + loaders: [ + { + test: /\.js$/, + exclude: /node_modules/, + loaders: ['monkey-hot', 'babel'] + }, + { + test: /\.css$/, + exclude: /node_modules/, + loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss') + }, + { + test: /\.scss$/, + exclude: /node_modules/, + loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss!sass?sourceMap') + }, + { + test: /\.(ttf|eot|svg)$/, + loader: 'url?limit=10000' + }, + { + test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'url?limit=10000&mimetype=application/font-woff' + }, + { + test: /\.(png|jpg|jpeg|gif)(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'file-loader' + } + ], + }, + resolve: { extensions: [ '', '.js', '.json' ] }, + externals: { + jquery: 'jQuery' + }, + plugins: [ + new Clean([sage.dist]), + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + 'window.jQuery': 'jquery', + 'window.Tether': 'tether' + }), + new AssetsPlugin({ + path: sage.dist, + filename: sage.manifest, + fullPath: false, + processOutput: assetsPluginProcessOutput, + }) + ], + postcss: [ autoprefixer ], + eslint: { + failOnWarning: false, + failOnError: true, + } +}; + +if ( SAGE_ENV === 'development' ) { + // development + webpackConfig.entry.main.push('webpack-hot-middleware/client?reload=true'); + webpackConfig.entry.customizer.push('webpack-hot-middleware/client?reload=true'); + webpackConfig.output.filename = '[name].js'; + webpackConfig.output.sourceMapFilename = '[file].map'; + webpackConfig.output.pathinfo = true; + webpackConfig.debug = true; + webpackConfig.devtool = '#cheap-module-source-map'; + webpackConfig.plugins.push(new webpack.optimize.OccurenceOrderPlugin()); + webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); + webpackConfig.plugins.push(new webpack.NoErrorsPlugin()); + webpackConfig.plugins.push(new ExtractTextPlugin('[name].css', { disable: !sage.extractStyles })); +} else { + // production + webpackConfig.output.filename = '[name].[hash].js'; + webpackConfig.output.sourceMapFilename = '[file].[hash].map'; + webpackConfig.plugins.push(new ExtractTextPlugin('[name].[hash].css')); + webpackConfig.plugins.push(new webpack.optimize.UglifyJsPlugin()); + webpackConfig.plugins.push(new OptimizeCssAssetsPlugin({ + cssProcessor: cssnano, + cssProcessorOptions: { discardComments: { removeAll: true } }, + canPrint: true + })); +} + +module.exports = webpackConfig;