├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json └── src ├── MixPugTask.js ├── PugSeeder.js ├── index.js └── logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [v0.3.0 (2019-03-01)](https://github.com/matejsvajger/laravel-mix-pug/compare/0.2.1...0.3.0) 4 | 5 | ### Fixed 6 | - Fixed compatibilty with laravel-mix v4 ([#10](https://github.com/matejsvajger/laravel-mix-pug/pull/10)) 7 | - Fixed typo in Readme.md -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Matej Svajger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-mix-pug 2 | Laravel Mix Plugin for compiling Pug/Jade templates. 3 | 4 |

5 | NPM 6 | NPM 7 | NPM 8 |

9 | 10 | ## Introduction 11 | 12 | This package provides a plugin for Laravel Mix to compile pug templates. `laravel-mix-pug` requires Laravel Mix to work. Please follow the instructions on how to use it on the package [repository](https://github.com/JeffreyWay/laravel-mix). 13 | 14 | ## Usage 15 | 16 | Install this package into your project: 17 | 18 | ``` 19 | npm install laravel-mix-pug --save-dev 20 | ``` 21 | Head over to your `webpack.mix.js` and register it on the Laravel Mix API: 22 | 23 | ```js 24 | let mix = require('laravel-mix'); 25 | mix.pug = require('laravel-mix-pug'); 26 | 27 | mix.js('src/app.js', 'dist') 28 | .sass('src/app.scss', 'dist') 29 | .pug('src/*.pug', 'dist') 30 | .setPublicPath('dist'); 31 | ``` 32 | 33 | ## Options 34 | You can also pass in a third optional parameter: *options* object. It accepts two options: 35 | 36 | ### seeds 37 | This is a path to a folder with seed files. Files can be of type `json` or `yaml`. They will be parsed and provided in your pug template locals under the seed file name and then contents. 38 | 39 | ```js 40 | mix.pug('src/*.pug', 'dist', {seeds:'src/seeds'}); 41 | ``` 42 | 43 | And if you have a file `demo.yml` in there all the content will be available in your template under 44 | 45 | ```pug 46 | a(href=seed.demo.anchor.link) seed.demo.anchor.name 47 | ``` 48 | 49 | ### locals 50 | It's possible to pass in an object which will be added to locals in your pug templates: 51 | 52 | ```js 53 | mix.pug('src/*.pug', 'dist', { 54 | locals: { 55 | config: { baseUrl: 'http://my-template.dev/' } 56 | } 57 | }); 58 | ``` 59 | 60 | and in your pug file: 61 | 62 | ```pug 63 | link(rel="stylesheet" media="screen" href=`{config.baseUrl}css/app.css`) 64 | script(src=`{config.baseUrl}js/main.js`) 65 | ``` 66 | 67 | ### pug 68 | You can pass in [pug config options](https://pugjs.org/api/reference.html#options) under `pug` key: 69 | 70 | ```js 71 | mix.pug('src/*.pug', 'dist', { 72 | pug: { 73 | pretty: true, 74 | debug: true 75 | } 76 | }); 77 | ``` 78 | 79 | ### ext && excludePath 80 | It is possible to change to output file extension and exclude part of the path. 81 | i.e.: You want your destination file to be in `resources/assets/views` and the folder structure in there to continue from the `resources/assets/pug/{..}`: 82 | 83 | ```js 84 | mix.pug('resources/assets/pug/*.pug', 'resources/assets/views', { 85 | ext: '.blade.php', 86 | excludePath: 'resources/assets/pug' 87 | }); 88 | ```` 89 | 90 | ## License 91 | 92 | Laravel Mix Pug is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-mix-pug", 3 | "version": "0.3.0", 4 | "description": "Laravel Mix Plugin for compiling Pug/Jade templates.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/matejsvajger/laravel-mix-pug.git" 12 | }, 13 | "keywords": [ 14 | "laravel", 15 | "mix", 16 | "pug" 17 | ], 18 | "author": "Matej Svajger ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/matejsvajger/laravel-mix-pug/issues" 22 | }, 23 | "homepage": "https://github.com/matejsvajger/laravel-mix-pug#readme", 24 | "dependencies": { 25 | "foldero": "^0.1.1", 26 | "glob": "^7.1.2", 27 | "js-yaml": "^3.9.1" 28 | }, 29 | "peerDependencies": { 30 | "laravel-mix": "^1.4.2 || 2.x || 3.x || 4.x" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/MixPugTask.js: -------------------------------------------------------------------------------- 1 | const FileCollection = require('laravel-mix/src/FileCollection'); 2 | const File = require('laravel-mix/src/File'); 3 | const Task = require('laravel-mix/src/tasks/Task'); 4 | const PugSeeder = require('./PugSeeder'); 5 | 6 | const notifier = require('node-notifier'); 7 | const glob = require('glob'); 8 | const path = require('path'); 9 | const pug = require('pug'); 10 | const fs = require('fs'); 11 | 12 | class MixPugTask extends Task { 13 | 14 | /** 15 | * Run the pug compiler. 16 | */ 17 | run() { 18 | 19 | let {files, dest, options} = this.data; 20 | 21 | if (!options) { 22 | options = { 23 | seeds: null, 24 | locals: {}, 25 | pug: null, 26 | ext: '.html', 27 | excludePath: null 28 | }; 29 | } 30 | 31 | // Set destination folder 32 | this.dest = dest; 33 | 34 | // Set pug options 35 | this.pugOptions = options.pug; 36 | 37 | // Setup template seeder 38 | this.seedPath = options.seeds; 39 | this.locals = options.locals || {}; 40 | this.extension = options.ext || '.html'; 41 | this.excludePath = options.excludePath || null; 42 | 43 | this.seeder = this.createSeeder(); 44 | 45 | // Prepare Template Files 46 | this.templates = files; 47 | 48 | // We'll be watching for changes on all pug files 49 | // in case a layout, mixin or partial changes and 50 | // all seed files included. 51 | this.files = new FileCollection( 52 | glob.sync('**/*.pug', {ignore: 'node_modules/**/*'}).concat( 53 | this.seeder.files 54 | ) 55 | ); 56 | 57 | // Preprare destination assets 58 | this.assets = files.map(asset => this.prepareAssets(asset)); 59 | 60 | this.compile(); 61 | } 62 | 63 | 64 | /** 65 | * Compiles a collection of Pug templates. 66 | * 67 | */ 68 | compile() { 69 | 70 | this.templates.forEach((template, index) => this.compileTemplate(template, index)); 71 | 72 | return this; 73 | } 74 | 75 | /** 76 | * Compiles a single pug template 77 | * 78 | * @param {string} src Path to the pug source file 79 | * @param {number} index 80 | */ 81 | compileTemplate(src, index) { 82 | let file = new File(src); 83 | let output = this.assets[index]; 84 | 85 | try { 86 | 87 | let template = pug.compileFile(file.path(), this.pugOptions); 88 | 89 | let html = template( 90 | this.seeder.locals 91 | ); 92 | 93 | fs.writeFileSync(output.path(), html); 94 | 95 | this.onSuccess(); 96 | 97 | } catch (e) { 98 | this.onFail(e.name + ': ' + e.message); 99 | } 100 | } 101 | 102 | /** 103 | * Updates seeder with changed data files 104 | * 105 | */ 106 | createSeeder() { 107 | return new PugSeeder(this.seedPath) 108 | .extend(this.locals); 109 | } 110 | 111 | /** 112 | * Recompile on change when using watch 113 | * 114 | * @param {string} updatedFile 115 | */ 116 | onChange(updatedFile) { 117 | this.seeder = this.createSeeder(); 118 | this.compile(); 119 | } 120 | 121 | 122 | /** 123 | * Handle successful compilation. 124 | * 125 | * @param {string} output 126 | */ 127 | onSuccess(output) { 128 | if (Config.notifications.onSuccess) { 129 | notifier.notify({ 130 | title: 'Laravel Mix', 131 | message: 'Pug Compilation Successful', 132 | contentImage: 'node_modules/laravel-mix-pug/src/logo.png' 133 | }); 134 | } 135 | } 136 | 137 | 138 | /** 139 | * Handle failed compilation. 140 | * 141 | * @param {string} output 142 | */ 143 | onFail(output) { 144 | console.log("\n"); 145 | console.log('Pug Compilation Failed!'); 146 | console.log(); 147 | console.log(output); 148 | 149 | if (Mix.isUsing('notifications')) { 150 | notifier.notify({ 151 | title: 'Laravel Mix', 152 | subtitle: 'Pug Compilation Failed', 153 | message: output, 154 | contentImage: 'node_modules/laravel-mix-pug/src/logo.png' 155 | }); 156 | } 157 | } 158 | 159 | relativePathFromSource(filePath, excludePath) { 160 | excludePath = excludePath || 'resources/assets/pug'; 161 | return filePath.split(excludePath).pop(); 162 | } 163 | 164 | prepareAssets(src) { 165 | let file = new File(src); 166 | let pathFromBase = this.relativePathFromSource(file.base(), this.excludePath); 167 | let baseDir = path.join(pathFromBase, this.dest); 168 | 169 | if (!File.exists(baseDir)) { 170 | new File(baseDir).makeDirectories(); 171 | } 172 | 173 | let output = path.join(baseDir, file.nameWithoutExtension() + this.extension); 174 | let asset = new File(output); 175 | 176 | return asset; 177 | } 178 | 179 | } 180 | 181 | module.exports = MixPugTask; 182 | -------------------------------------------------------------------------------- /src/PugSeeder.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const _ = require('lodash'); 3 | const glob = require('glob'); 4 | const yaml = require('js-yaml'); 5 | const foldero = require('foldero'); 6 | 7 | class PugSeeder { 8 | 9 | constructor(path) { 10 | 11 | this.path = path; 12 | this.files = path ? glob.sync(path + '/**/*.+(json|yaml|yml)') : []; 13 | this.locals = { 14 | seed: path ? this.parse(path) : null 15 | }; 16 | } 17 | 18 | /** 19 | * Parses all json|yaml files in the seed folder 20 | * and assigns them to locals object. 21 | * 22 | * @param {string} seedPath Path to directory with seed files 23 | */ 24 | parse(seedPath) { 25 | if (fs.existsSync(seedPath)) { 26 | return foldero(seedPath, { 27 | recurse: true, 28 | whitelist: '(.*/)*.+\.(json|ya?ml)$', 29 | loader: file => this.parseFile(file) 30 | }); 31 | } 32 | } 33 | 34 | /** 35 | * Parses a single seed file and 36 | * returns a representative object. 37 | * 38 | * @param {string} file path to seed file for parsing 39 | */ 40 | parseFile(file) { 41 | let json = {}; 42 | 43 | try { 44 | json = (path.extname(file).match(/^.ya?ml$/)) ? 45 | yaml.safeLoad(fs.readFileSync(file, 'utf8')): 46 | JSON.parse(fs.readFileSync(file, 'utf8')); 47 | } catch(e) { 48 | console.log(`Error Parsing DATA file: ${file}\n`); 49 | console.log('==== Details Below ====' + `\n${e.message}`); 50 | 51 | if (Mix.isUsing('notifications')) { 52 | notifier.notify({ 53 | title: 'Laravel Mix', 54 | subtitle: 'Pug Compilation Failed', 55 | message: e.message, 56 | contentImage: 'node_modules/laravel-mix-pug/src/logo.png' 57 | }); 58 | } 59 | } 60 | 61 | return json; 62 | } 63 | 64 | /** 65 | * Extends locals object with passed in object 66 | * 67 | * @param {object} data 68 | */ 69 | extend(data) { 70 | this.locals = _.extend(this.locals, data); 71 | return this; 72 | } 73 | 74 | } 75 | 76 | module.exports = PugSeeder; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | let Verify, Assert; 2 | // laravel-mix@1.x 3 | try { Verify = require('laravel-mix/src/Verify'); } 4 | // laravel-mix@>=2.x 5 | catch (e) { Assert = require('laravel-mix/src/Assert'); } 6 | 7 | const notifier = require('node-notifier'); 8 | const glob = require('glob'); 9 | 10 | function pug(src, dest, options) { 11 | 12 | // laravel-mix@1.x 13 | if (Verify != null) Verify.dependency('pug', ['pug'], true); 14 | // laravel-mix@>=2.x 15 | else Assert.dependencies(['pug'], true); 16 | 17 | let files = glob.sync(src); 18 | 19 | let MixPugTask = require('./MixPugTask'); 20 | 21 | Mix.addTask(new MixPugTask({ 22 | files, dest, options 23 | })); 24 | 25 | return this; 26 | } 27 | 28 | module.exports = pug; 29 | -------------------------------------------------------------------------------- /src/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matejsvajger/laravel-mix-pug/dc6d286adc27f7f78f8a79c648ffefd07fbd417d/src/logo.png --------------------------------------------------------------------------------