let Verify = require('./Verify'); let CopyFilesTask = require('./tasks/CopyFilesTask'); let ConcatFilesTask = require('./tasks/ConcatenateFilesTask'); let VersionFilesTask = require('./tasks/VersionFilesTask'); let webpack = require('webpack'); let glob = require('glob'); let _ = require('lodash'); let path = require('path'); class Api { /** * Register the Webpack entry/output paths. * * @param {string|Array} entry * @param {string} output */ js(entry, output) { Verify.js(entry, output); entry = [].concat(entry).map(file => new File(file)); output = new File(output); Config.js.push({ entry, output }); return this; } /** * Register support for the React framework. * * @param {string|Array} entry * @param {string} output */ react(entry, output) { Config.react = true; Verify.dependency('babel-preset-react', ['babel-preset-react']); return this.js(entry, output); }; /** * Register support for the Preact framework. * * @param {string|Array} entry * @param {string} output */ preact(entry, output) { Config.preact = true; Verify.dependency('babel-preset-preact', ['babel-preset-preact']); return this.js(entry, output); }; /** * Register support for the TypeScript. */ ts(entry, output) { Config.typeScript = true; Verify.dependency('ts-loader', ['ts-loader', 'typescript']); return this.js(entry, output); }; /** * Register support for the TypeScript. */ typeScript(entry, output) { return this.ts(entry, output); } /** * Register Sass compilation. * * @param {string} src * @param {string} output * @param {object} pluginOptions */ sass(src, output, pluginOptions = {}) { pluginOptions = Object.assign({ precision: 8, outputStyle: 'expanded' }, pluginOptions, { sourceMap: true }); return this.preprocess('sass', src, output, pluginOptions); } /** * Register standalone-Sass compilation that will not run through Webpack. * * @param {string} src * @param {string} output * @param {object} pluginOptions */ standaloneSass(src, output, pluginOptions = {}) { Verify.exists(src); return this.preprocess('fastSass', src, output, pluginOptions); }; /** * Alias for standaloneSass. * * @param {string} src * @param {string} output * @param {object} pluginOptions */ fastSass(...args) { return this.standaloneSass(...args); } /** * Register Less compilation. * * @param {string} src * @param {string} output * @param {object} pluginOptions */ less(src, output, pluginOptions) { Verify.dependency('less-loader', ['less-loader', 'less']); return this.preprocess('less', src, output, pluginOptions); } /** * Register Stylus compilation. * * @param {string} src * @param {string} output * @param {object} pluginOptions */ stylus(src, output, pluginOptions = {}) { Verify.dependency('stylus-loader', ['stylus-loader', 'stylus']); return this.preprocess('stylus', src, output, pluginOptions); }; /** * Register postcss compilation. * * @param {string} src * @param {string} output * @param {array} postCssPlugins */ postCss(src, output, postCssPlugins = []) { Verify.preprocessor('postCss', src, output); src = new File(src); output = this._normalizeOutput(new File(output), src.nameWithoutExtension() + '.css'); Config.preprocessors['postCss'] = (Config.preprocessors['postCss'] || []).concat({ src, output, postCssPlugins }); return this; }; /** * Register a generic CSS preprocessor. * * @param {string} type * @param {string} src * @param {string} output * @param {object} pluginOptions */ preprocess(type, src, output, pluginOptions = {}) { Verify.preprocessor(type, src, output); src = new File(src); output = this._normalizeOutput(new File(output), src.nameWithoutExtension() + '.css'); Config.preprocessors[type] = (Config.preprocessors[type] || []).concat({ src, output, pluginOptions }); if (type === 'fastSass') { Mix.addAsset(output); } return this; } /** * Combine a collection of files. * * @param {string|Array} src * @param {string} output * @param {Boolean} babel */ combine(src, output = '', babel = false) { output = new File(output); Verify.combine(src, output); if (typeof src === 'string' && File.find(src).isDirectory()) { src = _.pull( glob.sync(path.join(src, '**/*'), { nodir: true }), output.relativePath() ); } let task = new ConcatFilesTask({ src, output, babel }); Mix.addTask(task); return this; }; /** * Alias for this.Mix.combine(). * * @param {string|Array} src * @param {string} output */ scripts(src, output) { return this.combine(src, output); }; /** * Identical to this.Mix.combine(), but includes Babel compilation. * * @param {string|Array} src * @param {string} output */ babel(src, output) { return this.combine(src, output, true); return this; }; /** * Alias for this.Mix.combine(). * * @param {string|Array} src * @param {string} output */ styles(src, output) { return this.combine(src, output); }; /** * Minify the provided file. * * @param {string|Array} src */ minify(src) { if (Array.isArray(src)) { src.forEach(file => this.minify(file)); return this; } let output = src.replace(/\.([a-z]{2,})$/i, '.min.$1'); return this.combine(src, output); }; /** * Copy one or more files to a new location. * * @param {string} from * @param {string} to */ copy(from, to) { let task = new CopyFilesTask({ from, to: new File(to) }); Mix.addTask(task); return this; }; /** * Copy a directory to a new location. This is identical * to mix.copy(). * * @param {string} from * @param {string} to */ copyDirectory(from, to) { return this.copy(from, to); }; /** * Enable Browsersync support for the project. * * @param {object} config */ browserSync(config = {}) { Verify.dependency( 'browser-sync-webpack-plugin', ['browser-sync-webpack-plugin', 'browser-sync'], true ); if (typeof config === 'string') { config = { proxy: config }; } Config.browserSync = config; return this; }; /** * Enable automatic file versioning. * * @param {Array} files */ version(files = []) { Config.versioning = true; files = flatten([].concat(files).map(filePath => { if (File.find(filePath).isDirectory()) { filePath += (path.sep + '**/*'); } if (! filePath.includes('*')) return filePath; return glob.sync( new File(filePath).forceFromPublic().relativePath(), { nodir: true } ); })); Mix.addTask( new VersionFilesTask({ files }) ); return this; } /** * Register vendor libs that should be extracted. * This helps drastically with long-term caching. * * @param {Array} libs * @param {string} output */ extract(libs, output) { Config.extractions.push({ libs, output }); return this; }; /** * Enable sourcemap support. * * @param {Boolean} productionToo * @param {string} type */ sourceMaps(productionToo = true, type = 'inline-source-map') { if (Mix.inProduction()) { type = productionToo ? 'cheap-source-map' : false; } Config.sourcemaps = type; return this; }; /** * Override the default path to your project's public directory. * * @param {string} defaultPath */ setPublicPath(defaultPath) { Config.publicPath = path.normalize(defaultPath.replace(/\/$/, '')); return this; } /** * Set a prefix for all generated asset paths. * * @param {string} path */ setResourceRoot(path) { Config.resourceRoot = path; return this; }; /** * Disable all OS notifications. */ disableNotifications() { Config.notifications = false; return this; }; /** * Disable success notifications. */ disableSuccessNotifications() { Config.notifications = { onSuccess: false, onFailure: true }; return this; }; /** * Register libraries to automatically "autoload" when * the appropriate variable is references in your JS. * * @param {Object} libs */ autoload(libs) { let aliases = {}; Object.keys(libs).forEach(library => { [].concat(libs[library]).forEach(alias => { aliases[alias] = library; }); }); Config.autoload = aliases; return this; }; /** * Merge custom config with the provided webpack.config file. * * @param {object} config */ webpackConfig(config) { Config.webpackConfig = (typeof config == 'function') ? config(webpack) : config; return this; } /* Set Mix-specific options. * * @param {object} options */ options(options) { if (options.purifyCss) { options.purifyCss = require('./PurifyPaths').build(options.purifyCss); Verify.dependency( 'purifycss-webpack', ['purifycss-webpack', 'purify-css'], true // abortOnComplete ); } Config.merge(options); return this; }; /** * Register a Webpack build event handler. * * @param {Function} callback */ then(callback) { Mix.listen('build', callback); return this; } /** * Helper for determining a production environment. */ inProduction() { return Mix.inProduction(); } /** * Generate a full output path, using a fallback * file name, if a directory is provided. * * @param {Object} output * @param {Object} fallbackName */ _normalizeOutput(output, fallbackName) { if (output.isDirectory()) { output = new File(path.join(output.filePath, fallbackName)); } return output; } } module.exports = Api;