├── .gitignore ├── icons ├── fail.png ├── pass.png └── laravel.png ├── example ├── webpack.mix.js └── webpack.config.js ├── Manifest.js ├── package.json ├── Versioning.js ├── File.js ├── index.js └── Mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | notes.md -------------------------------------------------------------------------------- /icons/fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeffreyWay/laravel-webpacker/HEAD/icons/fail.png -------------------------------------------------------------------------------- /icons/pass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeffreyWay/laravel-webpacker/HEAD/icons/pass.png -------------------------------------------------------------------------------- /icons/laravel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeffreyWay/laravel-webpacker/HEAD/icons/laravel.png -------------------------------------------------------------------------------- /example/webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-webpacker').mix; 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for your application, as well as bundling up your JS files. 11 | | 12 | */ 13 | 14 | mix.js('src/app.js', 'dist/app.js') 15 | .sass('src/app.scss', 'dist/app.scss'); 16 | 17 | // Full API 18 | // mix.js(src, output); 19 | // mix.extract(vendorLibs); 20 | // mix.sass(src, output); 21 | // mix.less(src, output); 22 | // mix.combine(files, destination); 23 | // mix.copy(from, to); 24 | // mix.minify(file); 25 | // mix.sourceMaps(); // Enable sourcemaps 26 | // mix.version(); // Enable versioning. 27 | // mix.disableNotifications(); 28 | // mix.setCacheDirectory('some/folder'); 29 | -------------------------------------------------------------------------------- /Manifest.js: -------------------------------------------------------------------------------- 1 | let File = require('./File'); 2 | 3 | module.exports = class { 4 | /** 5 | * Create a new Manifest instance. 6 | * 7 | * @param {string} path 8 | */ 9 | constructor(path) { 10 | this.path = path; 11 | } 12 | 13 | 14 | /** 15 | * Determine if the manifest file exists. 16 | */ 17 | exists() { 18 | return File.exists(this.path); 19 | } 20 | 21 | 22 | /** 23 | * Retrieve the JSON output from the manifest file. 24 | */ 25 | read() { 26 | return JSON.parse( 27 | new File(this.path).read() 28 | ).assetsByChunkName; 29 | } 30 | 31 | 32 | /** 33 | * Write the updated stats to the manifest. 34 | * 35 | * @param {object} stats 36 | */ 37 | write(stats) { 38 | new File(this.path).write( 39 | JSON.stringify(stats.toJson()) 40 | ); 41 | } 42 | 43 | /** 44 | * Delete the given file from the manifest. 45 | * 46 | * @param {string} file 47 | */ 48 | remove(file) { 49 | new File(file).delete(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-webpacker", 3 | "version": "0.1.0", 4 | "description": "Laravel Mix is an elegant wrapper around Webpack for the 80% usecase.", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack --watch --progress --hide-modules", 8 | "hmr": "webpack-dev-server --inline --hot", 9 | "production": "export NODE_ENV=production && webpack --progress --hide-modules" 10 | }, 11 | "postcss": { 12 | "plugins": { 13 | "autoprefixer": {} 14 | } 15 | }, 16 | "keywords": [ 17 | "laravel", 18 | "webpack", 19 | "laravel elixir", 20 | "laravel mix" 21 | ], 22 | "author": "Jeffrey Way", 23 | "license": "MIT", 24 | "dependencies": { 25 | "babel-core": "^6.20.0", 26 | "babel-loader": "^6.2.9", 27 | "babel-preset-es2015": "^6.18.0", 28 | "clean-css": "^3.4.22", 29 | "concatenate": "0.0.1", 30 | "copy-webpack-plugin": "^4.0.1", 31 | "css-loader": "^0.26.1", 32 | "extract-text-webpack-plugin": "^2.0.0-beta.4", 33 | "file-loader": "^0.9.0", 34 | "fs": "0.0.1-security", 35 | "less": "^2.7.1", 36 | "less-loader": "^2.2.3", 37 | "node-sass": "^4.0.0", 38 | "on-build-webpack": "^0.1.0", 39 | "path": "^0.12.7", 40 | "postcss-load-config": "^1.0.0", 41 | "postcss-loader": "^1.2.1", 42 | "resolve-url-loader": "^1.6.1", 43 | "sass-loader": "^4.0.2", 44 | "style-loader": "^0.13.1", 45 | "uglify-js": "^2.7.5", 46 | "vue-loader": "^10.0.2", 47 | "vue-template-compiler": "^2.1.4", 48 | "webpack": "^2.1.0-beta.27", 49 | "webpack-dev-server": "^2.1.0-beta.12", 50 | "webpack-notifier": "^1.4.1" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Versioning.js: -------------------------------------------------------------------------------- 1 | let path = require('path'); 2 | let Manifest = require('./Manifest'); 3 | 4 | class Versioning { 5 | /** 6 | * Create a new Versioning instance. 7 | * 8 | * @param {object} manifest 9 | */ 10 | constructor(manifest) { 11 | this.enabled = false; 12 | this.manifest = manifest; 13 | 14 | this.files = []; 15 | } 16 | 17 | 18 | /** 19 | * Enable Webpack versioning. 20 | */ 21 | enable() { 22 | this.enabled = true; 23 | 24 | return this; 25 | } 26 | 27 | 28 | /** 29 | * Record versioned files. 30 | */ 31 | record() { 32 | if (! this.manifest.exists()) return; 33 | 34 | this.reset(); 35 | 36 | let json = this.manifest.read(); 37 | 38 | Object.keys(json).forEach(entry => { 39 | this.files = this.files.concat(json[entry]); 40 | }); 41 | 42 | return this; 43 | } 44 | 45 | 46 | /** 47 | * Reset all recorded files. 48 | */ 49 | reset() { 50 | this.files = []; 51 | 52 | return this; 53 | } 54 | 55 | 56 | /** 57 | * Replace all old hashed files with the new versions. 58 | * 59 | * @param {string} baseDir 60 | */ 61 | prune(baseDir) { 62 | let updated = new Versioning(this.manifest).enable().record(); 63 | 64 | if (! updated) return; 65 | 66 | this.files.forEach(file => { 67 | // If the updated file is exactly the same as the old 68 | // one, then nothing has changed. Don't delete it. 69 | if (! updated.files.includes(file)) { 70 | this.manifest.remove(path.join(baseDir, file)); 71 | } 72 | }); 73 | 74 | // Lastly, we'll replace the versioned file list with the new one. 75 | this.files = updated.files; 76 | 77 | return this; 78 | } 79 | } 80 | 81 | module.exports = Versioning; 82 | -------------------------------------------------------------------------------- /File.js: -------------------------------------------------------------------------------- 1 | let fs = require('fs'); 2 | let path = require('path'); 3 | let uglify = require('uglify-js'); 4 | let UglifyCss = require('clean-css'); 5 | 6 | module.exports = class { 7 | /** 8 | * Create a new File instance. 9 | * 10 | * @param {string} file 11 | */ 12 | constructor(file) { 13 | this.file = file; 14 | this.fileType = path.parse(file).ext; 15 | } 16 | 17 | 18 | /** 19 | * Minify the file, if it is CSS or JS. 20 | */ 21 | minify() { 22 | if (this.fileType === '.js') { 23 | this.write(uglify.minify(this.file).code); 24 | } 25 | 26 | if (this.fileType === '.css') { 27 | this.write( 28 | new UglifyCss().minify(this.read()).styles 29 | ); 30 | } 31 | } 32 | 33 | 34 | /** 35 | * Determine if the file exists. 36 | */ 37 | static exists(file) { 38 | return fs.existsSync(file); 39 | } 40 | 41 | 42 | /** 43 | * Read the file. 44 | */ 45 | read() { 46 | return fs.readFileSync(this.file, { encoding: 'utf-8' }); 47 | } 48 | 49 | 50 | /** 51 | * Write the given contents to the file. 52 | * 53 | * @param {string} body 54 | */ 55 | write(body) { 56 | fs.writeFileSync(this.file, body); 57 | } 58 | 59 | 60 | /** 61 | * Delete/Unlink the current file. 62 | */ 63 | delete() { 64 | if (fs.existsSync(this.file)) { 65 | fs.unlinkSync(this.file); 66 | } 67 | } 68 | 69 | 70 | /** 71 | * Parse the file path into segments. 72 | */ 73 | parsePath() { 74 | let outputSegments = path.parse(this.file); 75 | 76 | return { 77 | path: this.file, 78 | hashedPath: `${outputSegments.dir}/${outputSegments.name}.[hash]${outputSegments.ext}`, 79 | base: outputSegments.dir, 80 | file: outputSegments.base, 81 | hashedFile: `${outputSegments.name}.[hash]${outputSegments.ext}`, 82 | name: outputSegments.name, 83 | ext: outputSegments.ext 84 | }; 85 | } 86 | }; 87 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let path = require('path'); 2 | let Mix = require('./Mix'); 3 | 4 | /** 5 | * We'll fetch some Webpack config plugins here for cleanliness. 6 | */ 7 | module.exports.plugins = { 8 | WebpackNotifierPlugin: require('webpack-notifier'), 9 | WebpackOnBuildPlugin: require('on-build-webpack'), 10 | ExtractTextPlugin: require('extract-text-webpack-plugin'), 11 | CopyWebpackPlugin: require('copy-webpack-plugin') 12 | } 13 | 14 | 15 | /** 16 | * Register the Webpack entry/output paths. 17 | * 18 | * @param {mixed} entry 19 | * @param {string} output 20 | */ 21 | module.exports.js = (entry, output) => { 22 | Mix.js = { 23 | entry: path.resolve(entry), 24 | output: new Mix.File(output).parsePath(), 25 | vendor: false 26 | }; 27 | 28 | return this; 29 | }; 30 | 31 | 32 | /** 33 | * Register vendor libs that should be extracted. 34 | * This helps drastically with long-term caching. 35 | * 36 | * @param {array} libs 37 | */ 38 | module.exports.extract = (libs) => { 39 | Mix.js.vendor = libs; 40 | 41 | return this; 42 | } 43 | 44 | 45 | /** 46 | * Register Sass compilation. 47 | * 48 | * @param {string} src 49 | * @param {string} output 50 | */ 51 | module.exports.sass = (src, output) => { 52 | Mix.sass = { 53 | src: path.resolve(src), 54 | output: new Mix.File(output).parsePath() 55 | }; 56 | 57 | Mix.cssPreprocessor = 'sass'; 58 | 59 | return this; 60 | }; 61 | 62 | 63 | /** 64 | * Register Less compilation. 65 | * 66 | * @param {string} src 67 | * @param {string} output 68 | */ 69 | module.exports.less = (src, output) => { 70 | Mix.less = { 71 | src: path.resolve(src), 72 | output: new Mix.File(output).parsePath() 73 | }; 74 | 75 | Mix.cssPreprocessor = 'less'; 76 | 77 | return this; 78 | }; 79 | 80 | 81 | /** 82 | * Combine a collection of files. 83 | * 84 | * @param {string|array} src 85 | * @param {string} output 86 | */ 87 | module.exports.combine = (src, output) => { 88 | Mix.combine = (Mix.combine || []).concat({ src, output }); 89 | 90 | return this; 91 | }; 92 | 93 | 94 | /** 95 | * Copy one or more files to a new location. 96 | * 97 | * @param {string} from 98 | * @param {string} to 99 | */ 100 | module.exports.copy = (from, to) => { 101 | Mix.copy = (Mix.copy || []).concat({ 102 | from, 103 | to: path.resolve(__dirname, '../../', to) 104 | }); 105 | 106 | return this; 107 | }; 108 | 109 | 110 | /** 111 | * Minify the provided file. 112 | * 113 | * @param {string|array} src 114 | */ 115 | module.exports.minify = (src) => { 116 | Mix.minify = (Mix.minify || []).concat(src); 117 | 118 | return this; 119 | }; 120 | 121 | 122 | /** 123 | * Enable sourcemap support. 124 | */ 125 | module.exports.sourceMaps = () => { 126 | Mix.sourcemaps = (Mix.inProduction ? '#source-map' : '#inline-source-map'); 127 | 128 | return this; 129 | }; 130 | 131 | 132 | /** 133 | * Enable compiled file versioning. 134 | */ 135 | module.exports.version = () => { 136 | Mix.versioning.enabled = true; 137 | 138 | return this; 139 | }; 140 | 141 | 142 | /** 143 | * Disable all OS notifications. 144 | */ 145 | module.exports.disableNotifications = () => { 146 | Mix.notifications = false; 147 | 148 | return this; 149 | }; 150 | 151 | 152 | /** 153 | * Set the temporary cache directory. 154 | * 155 | * @param {string} path 156 | */ 157 | module.exports.setCacheDirectory = (path) => { 158 | Mix.cachePath = path; 159 | 160 | return this; 161 | }; 162 | 163 | 164 | module.exports.config = Mix; 165 | module.exports.mix = module.exports; 166 | -------------------------------------------------------------------------------- /Mix.js: -------------------------------------------------------------------------------- 1 | let path = require('path'); 2 | let File = require('./File'); 3 | let Manifest = require('./Manifest'); 4 | let Versioning = require('./Versioning'); 5 | let concatenate = require('concatenate'); 6 | 7 | module.exports = new class { 8 | /** 9 | * Create a new Laravel Mix instance. 10 | */ 11 | constructor() { 12 | this.inProduction = process.env.NODE_ENV === 'production'; 13 | this.File = File; 14 | this.hmr = false; 15 | this.sourcemaps = false; 16 | this.cssPreprocessor = false; 17 | this.notifications = true; 18 | 19 | this.publicPath = this.isUsingLaravel() ? 'public' : './'; 20 | this.cachePath = this.isUsingLaravel() ? 'storage/framework/cache' : './'; 21 | 22 | this.manifest = new Manifest(this.cachePath + '/Mix.json'); 23 | this.versioning = new Versioning(this.manifest); 24 | } 25 | 26 | 27 | /** 28 | * Finalize the user's webpack.mix.js configuration file. 29 | */ 30 | finalize() { 31 | // Since the user might wish to override the default cache 32 | // path, we'll update these here with the latest values. 33 | this.manifest.path = this.cachePath + '/Mix.json'; 34 | this.versioning.manifest = this.manifest; 35 | 36 | this.detectHotReloading(); 37 | } 38 | 39 | 40 | /** 41 | * Determine the Webpack entry file(s). 42 | */ 43 | entry() { 44 | if (this.cssPreprocessor) { 45 | return [this.js.entry, this[this.cssPreprocessor].src]; 46 | } 47 | 48 | return this.js.entry; 49 | } 50 | 51 | 52 | /** 53 | * Determine the Webpack output path. 54 | */ 55 | output() { 56 | let filename; 57 | 58 | if (this.js.vendor) { 59 | filename = this.versioning.enabled ? '[name].[hash].js' : '[name].js'; 60 | } else { 61 | filename = this.versioning.enabled ? this.js.output.hashedFile : this.js.output.file; 62 | } 63 | 64 | return { 65 | path: this.hmr ? '/' : this.publicPath, 66 | filename: path.join(this.js.output.base, filename).replace(this.publicPath, ''), 67 | publicPath: this.hmr ? 'http://localhost:8080/' : './' 68 | }; 69 | } 70 | 71 | 72 | /** 73 | * Minify the given files, or those from Mix.minify(). 74 | * 75 | * @param array|null files 76 | */ 77 | minifyAll(files = null) { 78 | if (! this.inProduction) return; 79 | 80 | files = files || this.minify || []; 81 | 82 | files.forEach(file => new File(file).minify()); 83 | 84 | return this; 85 | } 86 | 87 | 88 | /** 89 | * Combine the given files, or those from Mix.combine(). 90 | * 91 | * @param array|null files 92 | */ 93 | concatenateAll(files = null) { 94 | files = files || this.combine || []; 95 | 96 | files.forEach(file => { 97 | concatenate.sync(file.src, file.output); 98 | 99 | if (! this.inProduction) return; 100 | 101 | new this.File(file.output).minify(); 102 | }); 103 | 104 | return this; 105 | } 106 | 107 | 108 | /** 109 | * Detect if the user desires hot reloading. 110 | */ 111 | detectHotReloading() { 112 | let file = new this.File(this.cachePath + '/hot'); 113 | 114 | file.delete(); 115 | 116 | // If the user wants hot module replacement, we'll create 117 | // a temporary file, so that Laravel can detect it, and 118 | // reference the proper base URL for any assets. 119 | if (process.argv.includes('--hot')) { 120 | this.hmr = true; 121 | 122 | file.write('hot reloading enabled'); 123 | } 124 | } 125 | 126 | 127 | /** 128 | * Fetch the appropriate Babel config for babel-loader. 129 | * 130 | * @return {string} 131 | */ 132 | babelConfig() { 133 | let file = path.resolve(__dirname, '../../.babelrc'); 134 | 135 | // If the user has defined their own .babelrc file, 136 | // the babel-loader will automatically fetch it. 137 | // Otherwise, we'll use these defaults. 138 | return this.File.exists(file) ? '' : '?' + JSON.stringify({ 139 | "cacheDirectory": true, 140 | "presets": [ 141 | ["es2015", { "modules": false }] 142 | ] 143 | }); 144 | } 145 | 146 | 147 | /** 148 | * Determine if we are working with a Laravel project. 149 | */ 150 | isUsingLaravel() { 151 | return this.File.exists('./artisan'); 152 | } 153 | }; 154 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var Mix = require('laravel-webpacker').config; 4 | var plugins = require('laravel-webpacker').plugins; 5 | 6 | 7 | /* 8 | |-------------------------------------------------------------------------- 9 | | Mix Initialization 10 | |-------------------------------------------------------------------------- 11 | | 12 | | As our first step, we'll require the project's Laravel Mix file 13 | | and record the user's requested compilation and build steps. 14 | | Once those steps have been recorded, we may get to work. 15 | | 16 | */ 17 | 18 | require('./webpack.mix'); 19 | 20 | Mix.finalize(); 21 | 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Webpack Entry 26 | |-------------------------------------------------------------------------- 27 | | 28 | | We'll first specify the entry point for Webpack. By default, we'll 29 | | assume a single bundled file, but you may call Mix.extract() 30 | | to make a separate bundle specifically for vendor libraries. 31 | | 32 | */ 33 | 34 | module.exports.entry = { app: Mix.entry() }; 35 | 36 | if (Mix.js.vendor) { 37 | module.exports.entry.vendor = Mix.js.vendor; 38 | } 39 | 40 | 41 | 42 | /* 43 | |-------------------------------------------------------------------------- 44 | | Webpack Output 45 | |-------------------------------------------------------------------------- 46 | | 47 | | Webpack naturally requires us to specify our desired output path and 48 | | file name. We'll simply echo what you passed to with Mix.js(). 49 | | Note that, for Mix.version(), we'll properly hash the file. 50 | | 51 | */ 52 | 53 | module.exports.output = Mix.output(); 54 | 55 | 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Rules 60 | |-------------------------------------------------------------------------- 61 | | 62 | | Webpack rules allow us to register any number of loaders and options. 63 | | Out of the box, we'll provide a handful to get you up and running 64 | | as quickly as possible, though feel free to add to this list. 65 | | 66 | */ 67 | 68 | module.exports.module = { 69 | rules: [ 70 | { 71 | test: /\.vue$/, 72 | loader: 'vue-loader', 73 | options: { 74 | loaders: { 75 | js: 'babel-loader' + Mix.babelConfig() 76 | }, 77 | 78 | postcss: [ 79 | require('autoprefixer') 80 | ] 81 | } 82 | }, 83 | 84 | { 85 | test: /\.js$/, 86 | exclude: /(node_modules|bower_components)/, 87 | loader: 'babel-loader' + Mix.babelConfig() 88 | }, 89 | 90 | { 91 | test: /\.(png|jpg|gif)$/, 92 | loader: 'file-loader', 93 | options: { 94 | name: '[name].[ext]?[hash]' 95 | } 96 | }, 97 | 98 | { 99 | test: /\.(woff2?|ttf|eot|svg)$/, 100 | loader: 'file-loader', 101 | options: { 102 | name: path.relative(__dirname, './fonts/[name].[ext]?[hash]') 103 | } 104 | } 105 | ] 106 | }; 107 | 108 | 109 | if (Mix.sass) { 110 | module.exports.module.rules.push({ 111 | test: /\.s[ac]ss$/, 112 | loader: plugins.ExtractTextPlugin.extract({ 113 | fallbackLoader: 'style-loader', 114 | loader: [ 115 | 'css-loader', 'postcss-loader', 116 | 'resolve-url-loader', 'sass-loader?sourceMap' 117 | ] 118 | }) 119 | }); 120 | } 121 | 122 | 123 | if (Mix.less) { 124 | module.exports.module.rules.push({ 125 | test: /\.less$/, 126 | loader: plugins.ExtractTextPlugin.extract({ 127 | fallbackLoader: 'style-loader', 128 | loader: [ 129 | 'css-loader', 'postcss-loader', 130 | 'resolve-url-loader', 'less-loader?sourceMap' 131 | ] 132 | }) 133 | }); 134 | } 135 | 136 | 137 | 138 | /* 139 | |-------------------------------------------------------------------------- 140 | | Resolve 141 | |-------------------------------------------------------------------------- 142 | | 143 | | Here, we may set any options/aliases that affect Webpack's resolving 144 | | of modules. To begin, we will provide the necessary Vue alias to 145 | | load the Vue common library. You may delete this, if needed. 146 | | 147 | */ 148 | 149 | module.exports.resolve = { 150 | alias: { 151 | 'vue$': 'vue/dist/vue.common.js' 152 | } 153 | }; 154 | 155 | 156 | 157 | /* 158 | |-------------------------------------------------------------------------- 159 | | Stats 160 | |-------------------------------------------------------------------------- 161 | | 162 | | By default, Webpack spits a lot of information out to the terminal, 163 | | each you time you compile. Let's keep things a bit more minimal 164 | | and hide a few of those bits and pieces. Adjust as you wish. 165 | | 166 | */ 167 | 168 | module.exports.stats = { 169 | hash: false, 170 | version: false, 171 | timings: false 172 | }; 173 | 174 | module.exports.performance = { hints: Mix.inProduction }; 175 | 176 | 177 | 178 | /* 179 | |-------------------------------------------------------------------------- 180 | | Devtool 181 | |-------------------------------------------------------------------------- 182 | | 183 | | Sourcemaps allow us to access our original source code within the 184 | | browser, even if we're serving a bundled script or stylesheet. 185 | | You may activate sourcemaps, by adding Mix.sourceMaps(). 186 | | 187 | */ 188 | 189 | module.exports.devtool = Mix.sourcemaps; 190 | 191 | 192 | 193 | /* 194 | |-------------------------------------------------------------------------- 195 | | Webpack Dev Server Configuration 196 | |-------------------------------------------------------------------------- 197 | | 198 | | If you want to use that flashy hot module replacement feature, then 199 | | we've got you covered. Here, we'll set some basic initial config 200 | | for the Node server. You very likely won't want to edit this. 201 | | 202 | */ 203 | module.exports.devServer = { 204 | historyApiFallback: true, 205 | noInfo: true 206 | }; 207 | 208 | 209 | 210 | /* 211 | |-------------------------------------------------------------------------- 212 | | Plugins 213 | |-------------------------------------------------------------------------- 214 | | 215 | | Lastly, we'll register a number of plugins to extend and configure 216 | | Webpack. To get you started, we've included a handful of useful 217 | | extensions, for versioning, OS notifications, and much more. 218 | | 219 | */ 220 | 221 | module.exports.plugins = []; 222 | 223 | 224 | if (Mix.notifications) { 225 | module.exports.plugins.push( 226 | new plugins.WebpackNotifierPlugin({ 227 | title: 'Laravel Mix', 228 | alwaysNotify: true, 229 | contentImage: 'node_modules/laravel-webpacker/icons/laravel.png' 230 | }) 231 | ); 232 | } 233 | 234 | 235 | module.exports.plugins.push( 236 | function() { 237 | this.plugin('done', stats => Mix.manifest.write(stats)); 238 | } 239 | ); 240 | 241 | 242 | if (Mix.versioning.enabled) { 243 | Mix.versioning.record(); 244 | 245 | module.exports.plugins.push( 246 | new plugins.WebpackOnBuildPlugin(stats => { 247 | Mix.versioning.prune(Mix.publicPath); 248 | }) 249 | ); 250 | } 251 | 252 | 253 | if (Mix.combine || Mix.minify) { 254 | module.exports.plugins.push( 255 | new plugins.WebpackOnBuildPlugin(stats => { 256 | Mix.concatenateAll().minifyAll(); 257 | }) 258 | ); 259 | } 260 | 261 | 262 | if (Mix.copy) { 263 | Mix.copy.forEach(copy => { 264 | module.exports.plugins.push( 265 | new plugins.CopyWebpackPlugin([copy]) 266 | ); 267 | }); 268 | } 269 | 270 | 271 | if (Mix.js.vendor) { 272 | module.exports.plugins.push( 273 | new webpack.optimize.CommonsChunkPlugin({ 274 | names: ['vendor', 'manifest'] 275 | }) 276 | ); 277 | } 278 | 279 | 280 | if (Mix.cssPreprocessor) { 281 | let cssOutputPath = Mix[Mix.cssPreprocessor].output[ 282 | Mix.versioning.enabled ? 'hashedPath' : 'path' 283 | ]; 284 | 285 | module.exports.plugins.push( 286 | new plugins.ExtractTextPlugin({ 287 | filename: cssOutputPath.replace('public', '') 288 | }) 289 | ); 290 | } 291 | 292 | 293 | if (Mix.inProduction) { 294 | module.exports.plugins = module.exports.plugins.concat([ 295 | new webpack.DefinePlugin({ 296 | 'process.env': { 297 | NODE_ENV: '"production"' 298 | } 299 | }), 300 | 301 | new webpack.optimize.UglifyJsPlugin({ 302 | sourceMap: true, 303 | compress: { 304 | warnings: false 305 | } 306 | }), 307 | 308 | new webpack.LoaderOptionsPlugin({ 309 | minimize: true, 310 | options: { 311 | postcss: [ 312 | require('autoprefixer') 313 | ], 314 | context: __dirname, 315 | output: { path: './' } 316 | } 317 | }) 318 | ]); 319 | } 320 | --------------------------------------------------------------------------------