├── .gitignore ├── LICENSE ├── README.md ├── art ├── logo.png └── logo.svg ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log 3 | package-lock.json 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Daniel Hartmann 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 |

2 | 3 |

4 | 5 |

6 | Latest Version 7 | License 8 | Downloads 9 |

10 | 11 | # Laravel Mix SVG Vue 12 | 13 | **Extension to inline SVG files with Vue.js and optimize them automatically with SVGO.** 14 | 15 | ## Installation 16 | 17 | ```sh 18 | # npm 19 | npm install laravel-mix-svg-vue 20 | 21 | # yarn 22 | yarn add laravel-mix-svg-vue 23 | ``` 24 | 25 | Next require the extension inside your Laravel Mix config and call `svgVue()` in your pipeline: 26 | 27 | ```js 28 | // webpack.mix.js 29 | const mix = require('laravel-mix'); 30 | require('laravel-mix-svg-vue'); 31 | 32 | mix.js('resources/js/app.js', 'public/js') 33 | // .vue() // only necessary if you are using mix v6 34 | .svgVue(); 35 | ``` 36 | 37 | The last step is to import and register the Vue component, either for Vue 2 or 3. Notice the different imports for `SvgVue`: 38 | 39 | #### Vue 2 40 | 41 | ```js 42 | // e.g. app.js 43 | import Vue from 'vue'; 44 | import SvgVue from 'svg-vue'; 45 | 46 | Vue.use(SvgVue); 47 | 48 | const app = new Vue({ 49 | el: '#app' 50 | }); 51 | ``` 52 | 53 | #### Vue 3 54 | 55 | ```js 56 | // e.g. app.js 57 | import { createApp } from 'vue'; 58 | import SvgVue from 'svg-vue3'; 59 | 60 | const app = createApp({}); 61 | 62 | app.use(SvgVue); 63 | 64 | app.mount('#app'); 65 | ``` 66 | 67 | ## Usage 68 | 69 | To display your SVG files, all you need to do is pass the filename (and path if placed inside a subdirectory) to the Vue component: 70 | 71 | ```html 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ``` 81 | 82 | ## Options 83 | 84 | #### Default options 85 | 86 | If nothing is passed to the extension inside your Laravel Mix config, the following options will be used: 87 | 88 | ```js 89 | { 90 | svgPath: 'resources/svg', 91 | extract: false, 92 | svgoSettings: [ 93 | { removeTitle: true }, 94 | { removeViewBox: false }, 95 | { removeDimensions: true } 96 | ] 97 | } 98 | ``` 99 | 100 | #### Option details 101 | 102 | #### `svgPath` 103 | 104 | The path to your SVG files relative to the Laravel Mix config. 105 | 106 | #### `extract` 107 | 108 | If you wish to extract the SVG's to a separate file instead of including them in your main `app.js`, you can set this option to `true`. This will create a `svg.js` file which then needs to be loaded in your HTML. Make sure to load `app.js` before `svg.js`: 109 | 110 | ```html 111 | 112 | 113 | ``` 114 | 115 | #### `svgoSettings` 116 | 117 | Plugin configuration passed to SVGO. [See here](https://github.com/svg/svgo#built-in-plugins) for a list of available settings. 118 | 119 | #### Options overview 120 | 121 | Option | Type | Default | Description 122 | ---|---|---|--- 123 | `svgPath` | String | `resources/svg` | Path to your SVG files 124 | `extract` | Boolean | `false` | Separate the SVG's from your main bundle 125 | `svgoSettings` | Array | [{ removeTitle: true }, { removeViewBox: false }, { removeDimensions: true }] | SVGO settings 126 | 127 | ## Toggling or rendering icons inside lists 128 | 129 | Not really related to this extension, but when more than one `` icon is rendered inside a conditional state with `v-if` or `v-for`, a `key` attribute should be used to tell Vue that an element needs to change when any condition changes. 130 | 131 | While in most cases the cost for toggling elements with `v-show` should be preferred (also no need for a `key` attribute then), a simple example when toggling an icon with `v-if` inside a button could look like this: 132 | 133 | ```html 134 | 138 | 139 | 143 | ``` 144 | 145 | Rendering lists could be handled like this: 146 | 147 | ```html 148 | 154 | ``` 155 | 156 | Just remember the `key` has to be unique. More examples for this can be found in the Vue documentation. 157 | 158 | When toggling between elements that have the same tag name, you must tell Vue that they are distinct by giving them unique key attributes. Otherwise Vue’s compiler will only replace the content of the element for efficiency. Even when technically unnecessary though, it’s considered good practice to always key multiple items within a component. 159 | -------------------------------------------------------------------------------- /art/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielstgt/laravel-mix-svg-vue/ef7a49b18e850ef26c8cabc07f48c638b5476c1e/art/logo.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix'); 2 | let path = require('path'); 3 | const { extendDefaultPlugins } = require('svgo'); 4 | 5 | class SvgVue { 6 | 7 | name() { 8 | return 'svgVue'; 9 | } 10 | 11 | dependencies() { 12 | return ['svgo-loader', 'raw-loader', 'fs', 'svg-vue', 'svg-vue3']; 13 | } 14 | 15 | register(options) { 16 | this.options = Object.assign({ 17 | svgPath: 'resources/svg', 18 | extract: false, 19 | svgoSettings: [ 20 | { removeTitle: true }, 21 | { removeViewBox: false }, 22 | { removeDimensions: true } 23 | ] 24 | }, options); 25 | 26 | this.includePath = path.resolve(__dirname, process.cwd() + '/' + this.options.svgPath); 27 | } 28 | 29 | boot() { 30 | Mix.listen('configReady', config => { 31 | config.module.rules.map(r => { 32 | if (this._isSvgRegExp(r.test) && ! this._isSvgVueRule(r)) { 33 | r.exclude = path.resolve(__dirname, process.cwd() + '/' + this.options.svgPath); 34 | } 35 | }); 36 | }); 37 | } 38 | 39 | webpackRules() { 40 | return { 41 | test: /\.svg$/, 42 | include: [ 43 | this.includePath 44 | ], 45 | rules: [ 46 | { 47 | loader: 'raw-loader' 48 | }, 49 | 50 | { 51 | loader: 'svgo-loader', 52 | options: { 53 | plugins: extendDefaultPlugins(this._convertSvgoOptions(this.options.svgoSettings)) 54 | } 55 | } 56 | ] 57 | } 58 | } 59 | 60 | webpackConfig(webpackConfig) { 61 | let fs = require('fs'); 62 | 63 | fs.mkdir(this.includePath, error => { 64 | if (error && error.code === 'EEXIST') return null; 65 | }); 66 | 67 | webpackConfig.resolve.alias['svg-files-path'] = this.includePath; 68 | 69 | if (this.options.extract) { 70 | let svgAssetsObj = { 71 | test: this.includePath, 72 | name: '/js/svg', 73 | chunks: 'all', 74 | enforce: true 75 | } 76 | 77 | if (webpackConfig.optimization.hasOwnProperty('splitChunks')) { 78 | webpackConfig.optimization.splitChunks.cacheGroups['svgAssets'] = svgAssetsObj; 79 | } else { 80 | webpackConfig.optimization = { 81 | splitChunks: { 82 | cacheGroups: { 83 | svgAssets: svgAssetsObj 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | 91 | _isSvgRegExp(pattern) { 92 | let regExCheck = new RegExp(pattern); 93 | 94 | return regExCheck.test('.svg') || regExCheck.test('font.svg'); 95 | } 96 | 97 | _isSvgVueRule(rule) { 98 | if (rule.hasOwnProperty('include')) { 99 | return rule.include.includes(this.includePath); 100 | } 101 | 102 | return false; 103 | } 104 | 105 | _convertSvgoOptions(options) { 106 | let converted = []; 107 | 108 | options.forEach(option => { 109 | let settings = Object.keys(option); 110 | 111 | settings.forEach(setting => { 112 | converted.push({ 113 | name: setting, 114 | active: option[setting] 115 | }); 116 | }); 117 | }); 118 | 119 | return converted; 120 | } 121 | 122 | } 123 | 124 | mix.extend('svgVue', new SvgVue()); 125 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-mix-svg-vue", 3 | "version": "0.4.1", 4 | "description": "A Laravel Mix extension to inline SVG files with Vue.js and automatically optimize them with SVGO", 5 | "main": "index.js", 6 | "files": [ 7 | "index.js", 8 | "README.md", 9 | "package.json" 10 | ], 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/danielstgt/laravel-mix-svg-vue.git" 17 | }, 18 | "keywords": [ 19 | "laravel mix", 20 | "svg", 21 | "vue", 22 | "svgo" 23 | ], 24 | "author": "Daniel Hartmann", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/danielstgt/laravel-mix-svg-vue/issues" 28 | }, 29 | "homepage": "https://github.com/danielstgt/laravel-mix-svg-vue", 30 | "peerDependencies": { 31 | "laravel-mix": "^4.0.15 || ^5.0.0 || ^6.0.0" 32 | }, 33 | "dependencies": { 34 | "fs": "0.0.1-security", 35 | "path": "^0.12.7", 36 | "raw-loader": "^4.0.0", 37 | "svg-vue": "^0.2.0", 38 | "svg-vue3": "^0.2.1", 39 | "svgo": "^2.3.1", 40 | "svgo-loader": "^3.0.0" 41 | } 42 | } 43 | --------------------------------------------------------------------------------