├── .npmignore ├── .gitignore ├── .travis.yml ├── test ├── fixtures │ ├── basic.js │ ├── from-node-modules.js │ └── assets │ │ └── test.svg └── test.js ├── .github └── workflows │ └── tests.yml ├── rollup.config.js ├── package.json ├── index.js └── readme.md /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log 3 | 4 | dist/ 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 8 4 | - 10 5 | - 12 6 | -------------------------------------------------------------------------------- /test/fixtures/basic.js: -------------------------------------------------------------------------------- 1 | import svg from './assets/test.svg' 2 | 3 | expect(svg).to.be.instanceOf(Object) 4 | expect(svg.render).to.be.instanceOf(Function) 5 | 6 | const fakeVue = { 7 | _self: {}, 8 | $createElement: spy 9 | } 10 | // call render method 11 | svg.render.bind(fakeVue)() 12 | // count the number or time create element is called by function 13 | expect(spy.callCount).to.equal(5) 14 | -------------------------------------------------------------------------------- /test/fixtures/from-node-modules.js: -------------------------------------------------------------------------------- 1 | import svg from 'octicons/build/svg/alert.svg' 2 | 3 | expect(svg).to.be.instanceOf(Object) 4 | expect(svg.render).to.be.instanceOf(Function) 5 | 6 | const fakeVue = { 7 | _self: {}, 8 | $createElement: spy 9 | } 10 | // call render method 11 | svg.render.bind(fakeVue)() 12 | // count the number or time create element is called by function 13 | expect(spy.callCount).to.equal(5) 14 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Unit tests 2 | 3 | on: 4 | push: 5 | pull_request: 6 | branches: 7 | - "**" 8 | 9 | env: 10 | CI: true 11 | 12 | jobs: 13 | unit-test: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | node: [ '10', '12', '14' ] 18 | name: Unit Tests (Node ${{ matrix.node }}) 19 | steps: 20 | - uses: actions/checkout@v2 21 | - uses: actions/setup-node@v1 22 | with: 23 | node-version: ${{ matrix.node }} 24 | - run: | 25 | npm ci 26 | npm test 27 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import buble from '@rollup/plugin-buble'; 2 | import resolve from '@rollup/plugin-node-resolve'; 3 | 4 | const pkg = require('./package.json'); 5 | const external = Object.keys(pkg.dependencies).concat('path'); 6 | 7 | export default { 8 | input: 'index.js', 9 | plugins: [ 10 | resolve({ 11 | module: true, 12 | main: true, 13 | extensions: [ '.js' ] 14 | }), 15 | buble() 16 | ], 17 | external: external, 18 | output: [ 19 | { 20 | format: 'cjs', 21 | file: pkg['main'] 22 | }, 23 | { 24 | format: 'es', 25 | file: pkg['module'] 26 | } 27 | ] 28 | }; 29 | -------------------------------------------------------------------------------- /test/fixtures/assets/test.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 11 | 12 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rollup-plugin-vue-inline-svg", 3 | "version": "1.1.2", 4 | "description": "convert svg files to optimised vue components", 5 | "main": "dist/rollup-plugin-vue-inline-svg.js", 6 | "module": "dist/rollup-plugin-vue-inline-svg.es.js", 7 | "scripts": { 8 | "build": "rollup -c", 9 | "pretest": "npm run build", 10 | "test": "mocha test/*.js --requires buble/register", 11 | "prepublish": "npm test" 12 | }, 13 | "keywords": [ 14 | "rollup", 15 | "vue", 16 | "svg", 17 | "plugin" 18 | ], 19 | "author": "Benjamin Forster", 20 | "license": "ISC", 21 | "dependencies": { 22 | "@rollup/pluginutils": "^3.0.9", 23 | "svgo": "^1.3.2", 24 | "vue-template-compiler": "^2.6.11", 25 | "vue-template-es2015-compiler": "^1.9.1" 26 | }, 27 | "devDependencies": { 28 | "@rollup/plugin-buble": "^0.21.3", 29 | "@rollup/plugin-node-resolve": "^7.1.3", 30 | "chai": "^4.2.0", 31 | "mocha": "^7.1.1", 32 | "octicons": "^8.5.0", 33 | "rollup": "^2.6.1", 34 | "sinon": "^9.0.2", 35 | "standard": "^14.3.3" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const sinon = require('sinon') 3 | const { rollup } = require('rollup') 4 | const svg = require('../') 5 | 6 | const expect = chai.expect 7 | 8 | function makeBundle(options, stringOptions) { 9 | options.plugins = [svg(stringOptions)] 10 | return rollup(options) 11 | } 12 | 13 | describe('rollup-plugin-vue-inline-svg', () => { 14 | it('should import svg from file as a compiled vue component', () => { 15 | return makeBundle({ input: 'test/fixtures/basic.js' }, { include: '**/*.svg' }) 16 | .then(bundle => bundle.generate({ format: 'es', name: 'tpl' })) 17 | .then(({code, map}) => { 18 | const spy = sinon.spy() 19 | // run self testing code 20 | new Function('expect', 'spy', code)(expect, spy); 21 | }); 22 | }); 23 | it('should import svg from a node_module package as a compiled vue component', () => { 24 | return makeBundle({ input: 'test/fixtures/from-node-modules.js' }, { include: '**/*.svg' }) 25 | .then(bundle => bundle.generate({ format: 'es', name: 'tpl' })) 26 | .then(({code, map}) => { 27 | const spy = sinon.spy() 28 | new Function('expect', 'spy', code)(expect, spy); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { createFilter } from '@rollup/pluginutils'; 3 | import SVGO from 'svgo'; 4 | import compiler from 'vue-template-compiler'; 5 | import transpile from 'vue-template-es2015-compiler'; 6 | 7 | const optimizeSvg = (content, config, path) => new Promise((resolve, reject) => { 8 | const svgo = new SVGO(config); 9 | svgo.optimize(content, { path }).then((result) => { 10 | if (result.error) return reject(result.error); 11 | return resolve(result.data); 12 | }); 13 | }); 14 | 15 | export default function (options) { 16 | const include = options && options.include; 17 | const exclude = options && options.exclude; 18 | const config = options && options.svgoConfig || { plugins: ['removeDoctype', 'removeComments'] }; 19 | const filter = createFilter(include || '**/*.svg', exclude); 20 | return { 21 | name: 'vue-inline-svg', 22 | resolveId: function (source) { 23 | // Metches absolute paths 24 | // of svgs in node_modules 25 | // that are skipped by default in rollup 26 | var regexp = /^(?!\.)\S+\.svg$/gi; 27 | if (source.match(regexp)) { 28 | const id = path.resolve('node_modules/', source); 29 | return { id, external: false }; 30 | } 31 | return null; 32 | }, 33 | transform: (source, id) => { 34 | if (!filter(id)) return null; 35 | return optimizeSvg(source, config, id).then((result) => { 36 | const compiled = compiler.compile(result, { preserveWhitespace: false }); 37 | const transformed = transpile(`module.exports = { render: function () { ${compiled.render} } };`).replace('module.exports =', 'export default'); 38 | return transformed; 39 | }); 40 | }, 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # rollup-plugin-vue-inline-svg 2 | [![Unit tests](https://github.com/e-e-e/rollup-plugin-vue-inline-svg/actions/workflows/tests.yml/badge.svg)](https://github.com/e-e-e/rollup-plugin-vue-inline-svg/actions/workflows/tests.yml) 3 | 4 | A simple plugin to import svg files as vue components. This is intended to be used with [rollup-plugin-vue](https://www.npmjs.com/package/rollup-plugin-vue) and is based on [vue-svg-loader](https://www.npmjs.com/package/vue-svg-loader). 5 | 6 | ## installation 7 | 8 | ```sh 9 | npm install --save-dev rollup-plugin-vue-inline-svg 10 | ``` 11 | 12 | ## usage 13 | 14 | **rollup.config.js** 15 | ```js 16 | import svg from 'rollup-plugin-vue-inline-svg'; 17 | import vue from 'rollup-plugin-vue'; // optional 18 | 19 | export default { 20 | // ... 21 | plugins: [ 22 | svg(config) 23 | vue(), // optional 24 | ] 25 | } 26 | ``` 27 | 28 | ### config 29 | 30 | By default this plugin will attempt to transform all files that end with the extension `.svg`. 31 | You can be more explicit by passing include and exclude options. 32 | 33 | ```js 34 | // `include` and `exclude` can each be a minimatch 35 | // pattern, or an array of minimatch patterns, relative to process.cwd() 36 | { 37 | include: string or array of minimatch, 38 | exclude: string or array, 39 | svgoConfig: svgo config object, 40 | } 41 | ``` 42 | 43 | See [SVGO](https://github.com/svg/svgo) for configuration options that it accepts. 44 | 45 | ### Import svgs from `node_modules` 46 | 47 | The plugin is able to import svg files from `node_modules` packages: 48 | 49 | ```js 50 | import AlertSvg from 'octicons/build/svg/alert.svg' 51 | ``` 52 | 53 | The only important thing to remember is that the **rollup build process needs to be started from the project root directory** (e.g. via npm scripts). This is because the plugin will search the `node_modules` directory, via the `process.cwd()` [node method](https://nodejs.org/api/process.html#process_process_cwd), from where the process has started. 54 | --------------------------------------------------------------------------------