Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVG's that also render to web #265

Closed
LincMitch opened this issue Feb 15, 2018 · 14 comments
Closed

SVG's that also render to web #265

LincMitch opened this issue Feb 15, 2018 · 14 comments

Comments

@LincMitch
Copy link

In the basic-svg example it shows how to import Svg and prefixing Svg. elements.
import { render, Artboard, Svg } from 'react-sketchapp';
<Svg.Path ...

How would I render this same SVG code to the web npm run web? Just regular svg without the prefix <path ... I have a lot of svg icons in one file to render, so code duplication is not an option.

Could we even remove the prefix, and somehow declare that any <path should be interpreted as <Svg.Path?

This would make current SVG to sketch example much more powerful as its not really the single point of truth, unless the same code can be rendered to a final delivery platform.

@mathieudutour
Copy link
Collaborator

have a look at https://github.com/chengyin/react-primitives-svg which is the counter part of react-primitives for SVGs

@LincMitch
Copy link
Author

Fascinating, but I'm stuck.

I'm only familiar with npm run web or npm run render in package.json and seeing main.js or web.js files. It also seems really odd that the example.html file points to example.build.js but I only see a example.js file.
I have not yet run an example on ios or native which would be super cool to know how to do.

Any help on how to run these 4 examples?

@mathieudutour
Copy link
Collaborator

no but just use import Svg from 'react-primitives-svg' instead of import {Svg} from 'react-sketchapp' and your component can be rendered on both the web and Sketch

@LincMitch
Copy link
Author

Oh - I gotcha. Thx

@LincMitch
Copy link
Author

I added "react-primitives-svg": "^0.0.2", in dependencies to package.json
I got requires a peer warnings, so added peerDependencies.

  "peerDependencies": {
    "react": "~15.4.1",
    "react-native-svg": "*"
  }

Now the peer warnings say You must install peer dependencies yourself.
How do install peer dependencies?

However, they are just warnings. But npm run web throuws error:
Module not found: Error: Can't resolve './core'

@LincMitch
Copy link
Author

LincMitch commented Feb 17, 2018

Tried npm install react-primitives-svg
but still import Svg from 'react-primitives-svg'; throws this error:

Failed to compile with 1 error. ERROR in ./~/react-primitives-svg/lib/index.js Module not found: Error: Can't resolve './core' in '/Users/.../node_modules/react-primitives-svg/lib' @ ./~/react-primitives-svg/lib/index.js 1:17-34 @ ./src/web.js @ ./~/nwb/lib/reactRunEntry.js @ multi ./~/nwb/polyfills.js ./~/eventsource-polyfill/dist/browserify-eventsource.js ./~/webpack-hot-middleware/client.js ./~/nwb/lib/reactRunEntry.js

@LincMitch
Copy link
Author

LincMitch commented Feb 20, 2018

Finally got it working. Thx to Lynton Ye from https://learnreact.design/.

https://gist.github.com/lintonye/8e4d47dfb3089eae2462c5acced0030e

It also address' this issue #220 .

@johnnyBira
Copy link

johnnyBira commented Jun 29, 2018

@LincMitch, I also get the ...Module not found: Error: Can't resolve './core'... error.
Can you please elaborate what you did to fix it @LincMitch ?

@johnnyBira
Copy link

johnnyBira commented Jun 29, 2018

Okey, I sort of got it working by using an relative path to the web version, core.web.js:

import Svg from '../node_modules/react-primitives-svg/lib/core.web';

I noticed there's also a core.sketch.js and it would be nice to use this same package to handle the universal rendering.

The error me and @LincMitch mentioned above comes from the fact that the main file of react-primitives-svg required a module simply named core.js, which doesn't exist.
Is there some additional step to ensure it uses the correct primitive from the package based on the target platform?

@mathieudutour
Copy link
Collaborator

If you use webpack for bundling for the web, you will need to to add a resolve option like so:

{
  ...
  resolve: {
    // look for .web.js first
    extensions: ['.web.js', '.js', '.json'],
  },
  ...
}

If you use nwb like the examples, you need to create a nwb.config.js file with the following content:

module.exports = {
  webpack: {
    resolve: {
      // look for .web.js first
      extensions: ['.web.js', '.js', '.json'],
    },
  }
}

@SilentFlute
Copy link

mac os: 10.15.7
sketch version: 75 (129697)
react-sketchapp: latest edition

@LincMitch hey there, i have same problem: i also finding a way to convert <path to <Svg.Path, cuz i need render svg image from remote, may be from user pasted in or a server api, but both of them are string, like this sketch logo svg:

<svg xmlns="http://www.w3.org/2000/svg" width="494" height="447" viewBox="0 0 494 447">
  <g fill="none" fillRule="evenodd">
    <path fill="#FFAE00" d="M247 447L0 160 107 15 247 0l140 15 107 145" />
    <path fill="#EC6C00" d="M247 447L0 160h494" />
    <path fill="#FFAE00" d="M247 447L100 160h294" />
    <path fill="#FFEFB4" d="M247 0L100 160h294" />
    <path fill="#FFAE00" d="M107 15L52 88 0 160h101M387 15l55 73 52 72H393" />
    <path fill="#FED305" d="M107 15l-7 145L247 0m140 15l7 145L247 0" />
  </g>
</svg>

totally string...
but unfortunately, only this way can render a svg image correctly:

import * as React from 'react';
import { render, Artboard, Svg } from 'react-sketchapp';

const Document = () => {

  return (
    <Artboard
      name="my-image"
      style={{
        width: 1920,
        height: 1080
      }}
    >
      <Svg xmlns="http://www.w3.org/2000/svg" width="494" height="447" viewBox="0 0 494 447">
        <Svg.G fill="none" fillRule="evenodd">
          <Svg.Path fill="#FFAE00" d="M247 447L0 160 107 15 247 0l140 15 107 145" />
          <Svg.Path fill="#EC6C00" d="M247 447L0 160h494" />
          <Svg.Path fill="#FFAE00" d="M247 447L100 160h294" />
          <Svg.Path fill="#FFEFB4" d="M247 0L100 160h294" />
          <Svg.Path fill="#FFAE00" d="M107 15L52 88 0 160h101M387 15l55 73 52 72H393" />
          <Svg.Path fill="#FED305" d="M107 15l-7 145L247 0m140 15l7 145L247 0" />
        </Svg.G>
      </Svg>
    </Artboard>
  );
}

export default () => {
  render(<Document />, context.document.currentPage());
};

as shown above, i typed <Svg... directly in my editor, this means at the runtime right? this way it worked very well, but if the svg is string from user pasted in or a server api that i mentioned before, it won't work at all, i tried this way:

import * as React from 'react';
import { render, Artboard, Svg } from 'react-sketchapp';

const Document = ({ data }) => {
  const finalData = data
  .replace(/(<)(svg)/, (match, p1, p2) => (
    p2 = `${p1}${Svg}`
  ))
  .replace(/(<\/)(svg)(>)/, (match, p1, p2, p3) => (
    p2 = `${p1}${Svg}${p3}`
  ))
  .replace(/(<)(g)/, (match, p1, p2) => (
    p2 = `${p1}${Svg.G}`
  ))
  .replace(/(<\/)(g)(>)/, (match, p1, p2, p3) => (
    p2 = `${p1}${Svg.G}${p3}`
  ))
  .replace(/(<)(path)/, (match, p1, p2) => (
    p2 = `${p1}${Svg.Path}`
  ))

  return (
    <Artboard
      name="my-image"
      style={{
        width: 1920,
        height: 1080
      }}
    >
      {finalData}
    </Artboard>
  );
}

export default () => {
  fetch('http://localhost:3000/imgs/sketch.svg')
  .then(res => res.text())
  .then(
    response => {
      render(<Document data={response} />, context.document.currentPage());
    }
  )
};

i fetch a svg string from a server api, the response is a sketch log svg string, then i replace <svg with <Svg, then use it as Artboard's children, but i got a error with a redbox in sketch:

TypeError: undefined is not an object(evaluating 'props.transform')

processTransform

map

/Applications/Sketch.app/Contents/Resources/core-modules/

and i found this issue, i tried use:

import Svg from 'react-primitives-svg';

instead

import { Svg } from 'react-sketchapp';

but the error is the same...

so would u please give me some advices

@macintoshhelper
Copy link
Contributor

macintoshhelper commented Sep 16, 2021

@SilentFlute

i fetch a svg string from a server api, the response is a sketch log svg string, then i replace <svg with <Svg, then use it as Artboard's children, but i got a error with a redbox in sketch:

Hi, to render an SVG statically from a SVG string, you’ll need to use Babel to convert the string into React components. Fetching an SVG and trying to render it would’t work in React web either, you’d need to do it as a dynamic import and have it compiled by a Webpack loader.

I would suggest fetching and saving the SVG files locally as a file (can be done from a Node script), then using React svgr Webpack loader (modified to use react-primtives-svg or react-native Svg component to render it from an import.

This can be used as part of a CLI option, or a Node.js script to fetch and save the files, just need to do a replace of react-native-svg with react-sketchapp Svg: https://react-svgr.com/docs/options/#native

@SilentFlute
Copy link

@macintoshhelper thanks for reply, but may be i cant understand ur reply, i tried, but i failed

i check this issue: Svg did not rendered as expected and config my webpack.skpm.config.js as blow:

const path = require('path');

module.exports = (config) => {
  if (process.env.LOCAL_DEV) {
    config.module.rules[1].test = /^(?!.*\.(jsx?|tsx?|json|svg|md|nib|xib|framework|xcodeproj|xcworkspace|xcworkspacedata|pbxproj)$).*/;
    config.module.rules.push({
      test: /\.svg$/,
      use: [
        {
          loader: 'babel-loader',
          options: {
            presets: ['@skpm/babel-preset'],
          },
        },
        {
          loader: '@svgr/webpack',
          options: {
            native: true,
            svgoConfig: {
              plugins: [{ convertPathData: false }],
            },
            babel: false,
          },
        },
      ],
    });  
    config.resolve = {
      ...config.resolve,
      alias: {
        ...config.resolve.alias,
        'react-sketchapp': path.resolve(__dirname, '../../'),
      },
    };
  }
};

and installed all the loaders/packages i need, and u mentioned dynamic import, i use require, but still failed, obviously im wrong, but where is it, i cant found it, the repo is here: https://github.com/SilentFlute/react2sketch-svg.git

would u please take a while and do me a favor? that will be grateful, thanks again

@macintoshhelper
Copy link
Contributor

macintoshhelper commented Sep 17, 2021

You'll need to replace react-native-svg with react-sketchapp or react-primitives-svg. Code I used to do it:

webpack.skpm.config.js

    config.resolve = {
      ...config.resolve,
      alias: {
        ...config.resolve.alias,
        'react-sketchapp': path.resolve(__dirname, '../../'),
// PATCH <start>
        'react-native-svg': path.resolve(__dirname, './Svg.js'),
// PATCH <end>
      },
    };

./Svg.js

import React from 'react';
import { Svg } from 'react-sketchapp';

const {
  Circle,
  ClipPath,
  Defs,
  Ellipse,
  G,
  Image,
  Line,
  LinearGradient,
  Path,
  Pattern,
  Polygon,
  Polyline,
  RadialGradient,
  Rect,
  Stop,
  Symbol,
  Text,
  TextPath,
  TSpan,
  Use,
} = Svg;

// Disable masks in runtime
const Mask = () => <></>;
const _G = ({ mask, ...props }) => (mask ? <></> : <G {...props} />);

const _Use = ({ xlinkHref: href, ...props }) => <Use href={href} {...props} />;
const _Image = ({ xlinkHref: href, ...props }) => (
  <Image href={href} {...props} />
);

export {
  Mask,
  Circle,
  ClipPath,
  Defs,
  Ellipse,
  _G as G,
  _Image as Image,
  Line,
  LinearGradient,
  Path,
  Pattern,
  Polygon,
  Polyline,
  RadialGradient,
  Rect,
  Stop,
  Symbol,
  Text,
  TextPath,
  TSpan,
  _Use as Use,
};

export default Svg;

From here, you'll need to debug errors you run into, as the SVGs may contain stuff that is compatible in react-native-svg, but not react-sketchapp Svg, so try with a minimal SVG first.

Also, for the future, might be worth making a new issue for better visibility for others that want to import .svg files with Webpack, I don't think the process has been documented before; it’s separate to the original reason behind this issue 🙂 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants