GithubHelp home page GithubHelp logo

vite-plugin-solid-svg's Introduction

vite-plugin-solid-svg

Extend Vite with ability to use SVG files as Solid.js components.

Features:

  • SVGO optimization
  • Hot Module Replacement support
  • Support for ?component-solid query string
  • SSR

Currently supported Vite version:

4 or above

Install

yarn add --dev vite-plugin-solid-svg

pnpm i -D vite-plugin-solid-svg

Setup

// vite.config.js
import solidPlugin from 'vite-plugin-solid'
import solidSvg from 'vite-plugin-solid-svg'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [solidPlugin(), solidSvg()],
})

typescript

vite adds its own definition for "*.svg" and defines them as string. As far as I know this cannot be overridden. So we have two options: put our types before those of vite, or use imports with querystring.

If you are using defaultAsComponent which is the default, you need to put our types definition before vite in the tsconfig.

// tsconfig.json
"compilerOptions": {
  "types": [
    "vite-plugin-solid-svg/types-component-solid"
    "vite/client",
  ],
},

if you change to defaultAsComponent=false, you should use a different type definition that only identifies an svg import as a solid component when it matches the querystring. And in this case, put it before "vite/client"

// tsconfig.json
"compilerOptions": {
  "types": [
    "vite-plugin-solid-svg/types",
    "vite/client"
  ],
},
import MyIcon from './my-icon.svg';     // <-- this will match vite module definition, and therefore identified as string
import MyIcon from './my-icon.svg?component-solid';     // <-- this will match the definition in this plugin, and therefore identified as Solid Component

Options

SolidSvg({
  /**
   * If true, will export as JSX component if `as` isn't specified.
   *
   * Otherwise will export as url, or as JSX component if '?as=component-solid'
   *
   */
  defaultAsComponent: true,

  svgo: {
    enabled: true, // optional, by default is true
    svgoConfig: <svgo config>  // optional, if defined, the file svgo.config.js is not loaded.
  }
})

If you need to configure svgo, you can also create a config file svgo.config.js in the project's root, following the instructions at svgo docs. The svgo.svgoConfig has precedence over the file.

Usage

Import as a Solid.js component:

import MyIcon from './my-icon.svg?component-solid';
// or './my-icon.svg' if `defaultAsComponent` is `true`
import MyIcon from './my-icon.svg';

const App = () => {
  return (
    <div>
        <h1> Title </h1>
        <MyIcon />
    </div>
  );
};

export default App;

To import all svg inside a folder, use import.meta.glob('@/svgs/*.svg', { as: 'component-solid' }). See Vite docs for more details.

const icons = import.meta.glob('./*.svg', { as: 'component-solid' })

/*
  icons = {
    icon1: () => import("./icon1.svg"),
    icon2: () => import("./icon2.svg")
  }
*/

const App = () => {
  const Icon1 = lazy(() => iconsDic.icon1())
  return (
    <div>
        <p>hello</p><Icon1 />
    </div>
  );
};

export default App;

Why

In a Solidjs + vite project, you can easily add an svg image using:

import iconUrl from './icon.svg'

const App = () => {
  return (
    <div>
      <img href={iconUrl}>
    </div>
  )
}

However the fill color of the image cannot be overriden. Importing the svg as a component solves this and allows css styles to cascade into the svg content. Furthermore there may be situations where you'll need to ensure the image has been fully loaded, for example, before starting an animation. This module gives you a component that you can control when it's loaded.

Credits

This plugin is based on the work from the following projects:

vite-plugin-solid-svg's People

Contributors

jfgodoy avatar jfgodoy-afex avatar mrfoxpro avatar literalpie avatar blquinn avatar joosepalviste avatar zhengkyl avatar floer32 avatar

Stargazers

Rahul Yadav avatar Ceco Elijah Maples avatar Forrest Galloway avatar Erfan Mola avatar Sebastian Hancock avatar Садыков Айрат avatar  avatar Halu avatar David avatar  avatar Arturo Aguilera avatar Palm avatar O. Tadashi avatar Alek Angelov avatar Shiqi Mei avatar Steve Joiner avatar  avatar Ibrahim Ahmed avatar Soham Sarkar avatar  avatar Ben avatar CorrectRoad avatar Sergey avatar Matthew Chen avatar Benjamin Jasper avatar Lino avatar Ronen Eizen avatar Aiden avatar  avatar Mon avatar Dubzer avatar Jan Christoph Ebersbach avatar Autumn Saury avatar Jason_Huang avatar  avatar Liu Yike avatar Ionut Stoica avatar  avatar Front-end developer avatar João Graça avatar Russell Davis avatar Nathan Babcock avatar Daniel avatar Hajin Chung avatar Kenny Yang avatar Nikita avatar Franco RATOVOSON avatar  avatar TENTACLE  avatar Cody Ebberson avatar Zafar Ansari avatar  avatar Jorge Santiago avatar Aylo Srd avatar Damian Tarnawski avatar Usman Yunusov avatar ezzato avatar Andy Li avatar Julio Cesar Torres Cama avatar Cédric Eberhardt avatar Oren Elbaum avatar  avatar Darth Vader avatar Amir avatar Rail Khusnutdinov avatar  avatar Ricardo Valero de la Rosa avatar KyleFontenot avatar Duc-Thien Bui avatar Ignacio Zsabo avatar Not Existing avatar

Watchers

 avatar James Cloos avatar

vite-plugin-solid-svg's Issues

Any attributes passed to the component is being ignored

Whenever I try to pass role, id, or class no error shows in the IDE and the output HTML doesn't contain any of the inputted attributes.

I thought it might be SVGO, so I disabled it entirely, and the same issue exists.

Not sure if I am doing something wrong or if this is something that needs to be addressed.

The config:

solidSvg({
  defaultAsComponent: false,
  svgo: {
    svgoConfig: {
      removeViewBox: false,
    },
  },
}),

Package version:

"vite-plugin-solid-svg": "^0.7.0",
"solid-js": "^1.8.5",

Add option to use TypeScript defenisions with defaultAsComponent: true

Hi
I use this library and it works great!
I notice that when I use

 solidSvg({
        defaultAsComponent: true
      }),

option, the TypeScript definitions won't work (because they are not cover .svg without ?component-solid)
Can you provide another duplication type definitions that can be consumed if we use this defaultAsComponent?
Or I should just declare them myself?

Currently I added solid-svg.d.ts in my project with

declare module "*.svg" {
  import type { Component, ComponentProps } from "solid-js";
  const c: Component<ComponentProps<"svg">>;
  export default c;
}

Thanks!

Typescript error: Duplicate identifier 'src'

When compiling with TypeScript, I get the following error:

node_modules/vite-plugin-solid-svg/types-component-solid.d.ts:4:18 - error TS2300: Duplicate identifier 'src'.

4   export default c
                   ~

  node_modules/vite/client.d.ts:135:18
    135   export default src
                         ~~~
    'src' was also declared here.

node_modules/vite/client.d.ts:135:18 - error TS2300: Duplicate identifier 'src'.

135   export default src
                     ~~~

  node_modules/vite-plugin-solid-svg/types-component-solid.d.ts:4:18
    4   export default c
                       ~
    'src' was also declared here.

I believe this is because of the fact that this plugin replaces the built-in vite svg import.

How to make it work with Typescript

Hello, all is in the title, i try to make it work in Typescript.

Specifically in order to set the color of the SVG. But typescript tells me that the imported SVG is of type string, since vite resolve *.svg as string...

Do you have any insight ? On how to do it ?

Failure When Importing Third Party SVGs

import LogoutIcon from "@fortawesome/fontawesome-free/svgs/solid/sign-out-alt.svg"
12:36:55 AM [vite] Internal server error: ENOENT: no such file or directory, open 'src/@fortawesome/fontawesome-free/svgs/solid/sign-out-alt.svg

The plugin seems to always look in the ./src directory.

Error on build after update version 0.2.0

Hi, needed an update to version 0.2.0, because of SSR support. But build returns this error:

❯ yarn build
[vite:dts] File not found: /Users/lucasduarte/vxdk/src/modules/ui/icons/play.svg.tsx
file: src/modules/ui/icons/play.svg.tsx
error during build:
Error: File not found: /Users/lucasduarte/vxdk/src/modules/ui/icons/play.svg.tsx
    at DirectoryCoordinator.addSourceFileAtPath (/Users/lucasduarte/vxdk/node_modules/ts-morph/dist/ts-morph.js:18641:19)
    at Project.addSourceFileAtPath (/Users/lucasduarte/vxdk/node_modules/ts-morph/dist/ts-morph.js:20086:51)
    at Object.transform (/Users/lucasduarte/vxdk/node_modules/vite-plugin-dts/dist/index.js:141493:17)
    at /Users/lucasduarte/vxdk/node_modules/rollup/dist/shared/rollup.js:22681:25
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Original filename is play.svg, but build looking for play.svg.tsx

Is the same behavior with options or without options on solidSvg
My config:
image

Issues when defining extending environment variable types

I believe #27 may be addressing the same issue. I have a project that uses SolidStart, and the types for .svgs don't seem to be working properly.

image

My tsconfig.json:

{
	"compilerOptions": {
		"allowSyntheticDefaultImports": true,
		"esModuleInterop": true,
		"target": "ESNext",
		"module": "ESNext",
		"moduleResolution": "node",
		"jsxImportSource": "solid-js",
		"jsx": "preserve",
		"strict": true,
		"types": [
			"vite-plugin-solid-svg/types-component-solid",
			"solid-start/env"
		],
		"resolveJsonModule": true,
		"baseUrl": "./",
		"paths": {
			"~/*": ["./src/*"]
		}
	}
}

"readFile" is not exported by "__vite-browser-external"

I'm able to run and see SVGs during development, however when I attempt to build I get the following error:

"readFile" is not exported by "__vite-browser-external", imported by "node_modules/vite-plugin-solid-svg/dist/es/index.mjs".
1: import { readFile } from 'node:fs/promises';
            ^
2: import { loadConfig, optimize } from 'svgo';
error during build:
RollupError: "readFile" is not exported by "__vite-browser-external"

I've been able to repeat this issue with a bare-minimum code sandbox: https://codesandbox.io/p/sandbox/vite-solid-svgs-m5mvzw?file=%2Fsrc%2FApp.tsx%3A7%2C19

You will see the SVG rendered properly but if you attempt to run yarn build it will throw the error.

Type 'Component<SvgSVGAttributes<SVGSVGElement>>' is not assignable to type 'string | Element'.

I don't know if this is really an issue because this code build and run without any problmes (so far at least) but this error is anoying.
No idea how to fix, anyone can help?

Minimal example here:

interface ItemProps {
  icon: Component<JSX.SvgSVGAttributes<SVGSVGElement>>;
  label: string;
  active?: boolean;
}

const Item: Component<ItemProps> = (props) => {
  const Icon = props.icon;
  return (
    <div class={props.active ? activeItemClass : baseItemClass}>
      {props.icon} {/* Type 'Component<SvgSVGAttributes<SVGSVGElement>>' is not assignable to type 'string | Element'. */}
      {props.label}
      </div>
  );
};

My tsconfig:

{
  "compilerOptions": {
    "strict": true,
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "jsx": "preserve",
    "jsxImportSource": "solid-js",
    "types": [
      "vite-plugin-solid-svg/types-component-solid",
      "vite/client"
    ],
    "noEmit": true,
    "isolatedModules": true,
    "baseUrl": "./src",
    "paths": {
      "@components/*": ["components/*"],
      "@api/*": ["api/*"],
      "@pages/*": ["pages/*"],
      "@assets/*": ["assets/*"],
      "@images/*" : ["assets/images/*"],
    }
  }
}

Current "fix":

const Item: Component<ItemProps> = (props) => {
  const Icon = props.icon;
  return (
    <div class={props.active ? activeItemClass : baseItemClass}>
      {// @ts-ignore
      props.icon}
      {props.label}
      </div>
  );
};

this plugin doesn't work with solid-start/vite

this was working fine with vite-plugin-solid but doesn't seem to be working with solid-start/vite. The imports don't work and you get a Comp is not a function error. Feel like this is important since Solid Start is basically the create-next-app for SolidJS.

Pass props.children

I want to add some elements inside svg. For example:

<Icon
   classList={{
      active: editor.tool === type,
   }}
   onClick={[onClick, type]}
   children={<title>I'm a circle</title>}
  >
<title>{t().icon_title}</title>
</Icon>

How is it possible to achieve this?

version 0.8.0

Hi, I noticed that v0.8.0 is the latest version according to npm info vite-plugin-solid-svg, but v0.7.0 is the latest according to the changelog and the main branch.

Also, TS is unable to find the appropriate types in v0.8.0 because in package.json exports['.'].types doesn't exist.

I'm not sure if 0.8.0 is an unintentional/unsupported release, or if the main branch of this repo is somehow out of date. Either way, I think something is off here.

Style element error

Im not sure what the cause is, but when i try to use this plugin with an svg with a style block in it, it errors like so:

Unexpected token, expected "}" (1:255)

The character it is referring to is the first colon from the style block

How to dynamically import svg file?

I'm trying to do dynamic import svg file based on user select, such as:

import { onMount } from "solid-js";

export const DynaSvg = (props) => {

  let SvgComp;
  onMount(async () => {
    SvgComp = await import(`./${props.name}.svg`);
    console.log(SvgComp);
    // SvgComp.ref = props.parentRef;
  });

 return (
  <Show when={SvgComp}>
    <div>
      <SvgComp />
    </div>
  </Show>
)
};

But it doesn't work, is there anyway to do this?

Resize issue

Sorry maybe I'm just doing something stupid but I cant seem to resize the SVG by using the width attribute, inline style for width or tailwind. Setting these attributes just crops the svg. Am I missing something or does this plugin not support resizing?
Using transform/scale distorts the SVG and it continues taking up space of the original svg.

Plugin prevents loading a page when the URL path ends with "svg"

Hello,

Using this plugin prevents the Vite development server from loading the document/web page (the request with header Sec-Fetch-Dest: document) when the URL path ends with svg.

Examples:

  • (re)load page on /my-tab-to-demo-svg fails
  • (re)load page on /my-tab-to-demo-canvas works

Error case

ENOENT: no such file or directory, open 'C:\my-tab-to-demo-svg'

Page displays:

image

Working case

Page displays:

image

Additional information

Dependencies

{
    "vite": "4.4.11",
    "vite-plugin-solid": "2.7.0",
    "vite-plugin-solid-svg": "0.6.4"
}

Vite configuration file

import {defineConfig} from 'vite';
import solid from 'vite-plugin-solid';
import solidSvg from 'vite-plugin-solid-svg';

export default defineConfig({
    plugins: [solid(), solidSvg()],
});

Entry point for test

document.body.innerText = location.pathname; // it loading succeeded, will show the URL path, simply

Possible solutions

The first one would be to check for .svg instead of svg, unless I'm missing a rationale for not doing so.

One could argue that they would still want to have the document/web page load on a URL like /my.tab.to.demo.svg and that it would fail again then, but it actually fails much before on the Vite side, which apparently falls back to trying to load a physical entry point that would be located at /my.tab.to.demo.svg (fair enough, though it could check only for html extensions or simply fallback to default entry point, but I may miss more use cases with MPA and SSR).

Second solution would be to simply ignore any content that comes from a request with Sec-Fetch-Dest: document since it's supposed to load the application entry point, which I guess this plugin is not for. Btw, loading an SVG file from the public folder seems to not even go through the plugin at all anyways.

However, for that second solution, I'm not even sure there's a way to know the details of the request that triggered a pass through the plugins.

Support for SSR

Hi, I'n using this plugin on Solid Start SSR and got this error
Screenshot_20211130-112624
And looks like it's hardcoded for client-side rendering and not for server-side rendering. Can you make it not hardcoded and/or make it compatible with both CSR and SSR?

Removes the viewBox attribute

It seems like this plugin removes the width, height, and viewBox attributes (really, all attributes) and replaces them with a single {...props} spread. This is somewhat problematic for icon libraries. For instance, when using https://github.com/tabler/tabler-icons I have to pass width={24} height={24} viewBox="0 0 24 24" in order for scaling to work properly. If you look at any given React icon they ship, e.g., https://github.com/tabler/tabler-icons/blob/4a066745bf1df56615cf0077da906e60842196c4/icons-react/icons-js/123.js, you can see that width/height/viewBox are all preserved.

It would be great if there were an option to preserve some or all attributes in source svg files.

`Comp is not a function` when testing a component that has an exported SVG

When rendering a component that includes an imported svg using solid-testing-library it throws a TypeError: Comp is not a function.

Component code

<For each={props.items()}>{props.renderItem}</For>
          <Show when={props.infiniteScroll !== undefined}>
            <div
              use:observer={(el) => {
                if (el.isIntersecting) props.infiniteScroll?.onLoadMore?.();
              }}
              class="py-2"
            >
              <Spinner />
            </div>
          </Show>

Test suite

it('renders items', () => {
  const itemsResponse = ['1', '2'];
  const [items] = createSignal(itemsResponse);
  const { getByText } = renderDropdown({ items });
  
  expect(getByText(itemsResponse[0])).toBeInTheDocument();
});

This test suite, and all the others, pass when removing the SVG. Any thoughts on this? Thanks in advance

SVGO config isn't working when importing as component

Try to create svg.config.js in project root:

module.exports = {
   multipass: true, // boolean. false by default
   datauri: 'enc', // 'base64' (default), 'enc' or 'unenc'.
   js2svg: {
      indent: 2, // string with spaces or number of spaces. 4 by default
      pretty: true, // boolean, false by default
   },
   plugins: [
      // set of built-in plugins enabled by default
      'preset-default',

      // enable built-in plugins by name
      'prefixIds',

      // or by expanded notation which allows to configure plugin
      {
         name: 'sortAttrs',
         params: {
            xmlnsOrder: 'alphabetical',
         },
      },
   ],
}

You will see errors:
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.