Skip to content

Commit

Permalink
Change the way of importing SVGs as Vue components
Browse files Browse the repository at this point in the history
Previously to use SVG file as a component you would need to add `?component` to the path of the imported SVG file. That caused a lot of issues for both build process and tests, as neither Rollup nor Jest supports query string in the file path.
  • Loading branch information
visualfanatic committed Jun 14, 2020
1 parent 98f3a95 commit 5b0dc9b
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 21 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ Vite is currently in an experimental state which means this plugin will change a

#### Currently supported Vite version:

<p><code>0.20.4</code></p>
<p><code>0.20.8</code></p>

### Install

```bash
yarn add --dev vite-plugin-svg @vue/compiler-dom
yarn add --dev vite-plugin-svg

npm i -D vite-plugin-svg @vue/compiler-dom
npm i -D vite-plugin-svg
```

### Usage

To use SVG file as a Vue component you need to append `?component` query string to the path of your file.
Starting from `v0.4.0` to use SVG file as a component, just import `VueComponent` from the path of the file.
This gives you more control over how a particular SVG file should be loaded and processed:

```js
Expand All @@ -48,7 +48,7 @@ img.src = myIconUrl;
</div>
</template>
<script>
import MyIcon from './svgs/my-icon.svg?component'; // Note the `?component` part
import { VueComponent as MyIcon } from './svgs/my-icon.svg';
export default {
components: {
Expand Down
46 changes: 30 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
const { compile } = require('@vue/compiler-dom');
const { compileTemplate } = require('@vue/compiler-sfc');
const { join } = require('path');
const { readFileSync } = require('fs');
const SVGO = require('svgo');

async function compileSvg(code, path, isBuild) {
const { code: compiledCode } = compile(code, {
mode: 'module',
runtimeModuleName: isBuild ? undefined : '/@modules/vue',
async function compileSvg(source, path, isBuild) {
let { code } = compileTemplate({
source,
transformAssetUrls: false,
});

return `
${compiledCode.replace('export ', '')}
code = code.replace('export function render', 'function render');
code += '\nconst VueComponent = { render };';

export default {
render,
__hmrId: ${JSON.stringify(path)}
}
`;
if (!isBuild) {
code += `\nVueComponent.__hmrId = ${JSON.stringify(path)};`;
}

code += `\nexport { VueComponent };`;

return code;
}

async function optimizeSvg(svgo, content, path) {
Expand All @@ -33,21 +37,31 @@ module.exports = (options = {}) => {
return {
transforms: [
{
test: (path, query) => path.endsWith('.svg') && query.component != null,
transform: async (code, isImport, isBuild, path) => {
test: (path, query) => {
const isSVG = path.endsWith('.svg');

return process.env.NODE_ENV === 'production'
? isSVG
: isSVG && query.import != null;
},
transform: async (transformedCode, _, isBuild, path) => {
let result = cache.get(path);

if (!result) {
const code = readFileSync(
isBuild ? path : join(process.cwd(), path),
);

const svg = await optimizeSvg(svgo, code, path);

result = await compileSvg(svg, path, isBuild);

if (isBuild) {
cache.set(id, result);
cache.set(path, result);
}
}

return result;
return `${transformedCode}\n${result}`;
},
},
],
Expand Down

0 comments on commit 5b0dc9b

Please sign in to comment.