nrwl / nx

Smart Monorepos ยท Fast CI
https://nx.dev
MIT License
23.45k stars 2.33k forks source link

Importing SVG assets directly from TypeScript/JavaScript appears broken #14378

Closed jamieathans closed 1 year ago

jamieathans commented 1 year ago

Current Behavior

As documented in Adding Images, Fonts, and Files, importing an SVG and referencing it in an HTML img tag appears broken.

Using NX 15.5.1, the generated HTML is:

<img src="http://localhost:8081/logo.svg">

Using NX 15.4.5, the generated HTML is:

<img src="http://localhost:8081/logo.8f643a94aabfcf565a9b934459ac7b98.svg">

Expected Behavior

As documented in Adding Images, Fonts, and Files, importing an SVG and referencing it in an HTML img tag should work.

It was working correctly using NX 15.4.5.

Github Repo

No response

Steps to Reproduce

Import an SVG and reference it in an img tag as described here - Adding Images, Fonts, and Files.

Nx Report

Node : 18.13.0
   OS   : darwin arm64
   npm  : 8.19.3

   nx : 15.5.1
   @nrwl/angular : Not Found
   @nrwl/cypress : 15.5.1
   @nrwl/detox : Not Found
   @nrwl/devkit : 15.5.1
   @nrwl/esbuild : Not Found
   @nrwl/eslint-plugin-nx : 15.5.1
   @nrwl/expo : Not Found
   @nrwl/express : Not Found
   @nrwl/jest : 15.5.1
   @nrwl/js : 15.5.1
   @nrwl/linter : 15.5.1
   @nrwl/nest : Not Found
   @nrwl/next : Not Found
   @nrwl/node : Not Found
   @nrwl/nx-cloud : Not Found
   @nrwl/nx-plugin : Not Found
   @nrwl/react : 15.5.1
   @nrwl/react-native : Not Found
   @nrwl/rollup : 15.5.1
   @nrwl/schematics : Not Found
   @nrwl/storybook : 15.5.1
   @nrwl/web : 15.5.1
   @nrwl/webpack : 15.5.1
   @nrwl/workspace : 15.5.1
   @nrwl/vite : 15.5.1
   typescript : 4.8.4
   ---------------------------------------
   Local workspace plugins:
   ---------------------------------------
   Community plugins:

Failure Logs

No response

Additional Information

Using NX 15.5.1, the appears t be 2 generated assets:

var _g;
var _excluded = ["title", "titleId"];
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
import * as React from "react";
import { forwardRef } from "react";
var SvgLogo = function SvgLogo(_ref, ref) {
  var title = _ref.title,
    titleId = _ref.titleId,
    props = _objectWithoutProperties(_ref, _excluded);
  return /*#__PURE__*/React.createElement("svg", _extends({
    xmlns: "http://www.w3.org/2000/svg",
    x: 0,
    y: 0,
    width: 310,
    height: 77.303,
    viewBox: "0, 0, 310, 77.303",
    ref: ref,
    "aria-labelledby": titleId
  }, props), title ? /*#__PURE__*/React.createElement("title", {
    id: titleId
  }, title) : null, _g || (_g = /*#__PURE__*/React.createElement("g", {
    id: "Layer_1"
  }, /*#__PURE__*/React.createElement("path", {
    d: "M99.578,25.851 L117.992,25.851 L117.992,30.5 L104.264,30.5 L104.264,36.01 L114.748,36.01 L114.748,40.732 L104.264,40.732 L104.264,51.505 L99.578,51.505 L99.578,25.851",
    fill: "#000000"
  }), /*#__PURE__*/React.createElement("path", {
    d: "M127.984,46.859 L131.586,46.859 L131.586,30.5 L127.984,30.5 L127.984,25.851 L139.909,25.851 L139.909,30.5 L136.307,30.5 L136.307,46.859 L139.909,46.859 L139.909,51.505 L127.984,51.505 L127.984,46.859",
    fill: "#000000"
  }), /*#__PURE__*/React.createElement("path", {
    d: "M150.659,31.902 C150.009,29.886 149.865,29.778 149.865,27.039 L149.865,25.851 L154.37,25.851 L154.37,27.617 C154.37,28.264 154.406,28.806 154.586,29.453 L159.055,44.406 L163.521,29.453 C163.701,28.806 163.737,28.264 163.737,27.617 L163.737,25.851 L168.242,25.851 L168.242,27.039 C168.242,29.778 168.098,29.886 167.448,31.902 L161.288,51.505 L156.819,51.505 L150.659,31.902",
    fill: "#000000"
  }), /*#__PURE__*/React.createElement("path", {
    d: "M178.52,25.851 L196.93,25.851 L196.93,30.5 L183.202,30.5 L183.202,36.01 L193.689,36.01 L193.689,40.732 L183.202,40.732 L183.202,46.859 L196.93,46.859 L196.93,51.505 L178.52,51.505 L178.52,25.851",
    fill: "#000000"
  }), /*#__PURE__*/React.createElement("path", {
    d: "M207.46,44.659 L207.46,32.697 C207.46,28.914 210.52,25.851 214.306,25.851 L219.061,25.851 C222.554,25.851 225.401,28.445 225.871,31.83 L221.474,33.022 L221.221,32.336 C220.791,31.147 220.358,30.5 219.277,30.5 L214.053,30.5 C212.97,30.5 212.106,31.4 212.106,32.48 L212.106,44.875 C212.106,45.956 212.97,46.859 214.053,46.859 L219.205,46.859 C220.285,46.859 220.896,46.245 221.221,45.02 L221.402,44.334 L225.798,45.486 C225.365,48.911 222.518,51.505 219.025,51.505 L214.306,51.505 C210.52,51.505 207.46,48.441 207.46,44.659",
    fill: "#000000"
  }), /*#__PURE__*/React.createElement("path", {
    d: "M247.138,42.173 L244.472,33.597 L241.805,42.173 L247.138,42.173 z M235.284,49.666 C235.284,48.441 235.321,47.972 235.678,46.819 L242.239,25.851 L246.704,25.851 L253.261,46.819 C253.623,47.972 253.659,48.441 253.659,49.666 L253.659,51.505 L249.157,51.505 L249.157,49.63 C249.157,49.272 249.157,48.983 249.085,48.766 L248.543,46.786 L240.4,46.786 L239.858,48.766 C239.789,48.983 239.789,49.272 239.789,49.63 L239.789,51.505 L235.284,51.505 L235.284,49.666",
    fill: "#000000"
  }), /*#__PURE__*/React.createElement("path", {
    d: "M263.401,45.486 L267.794,44.334 L268.011,45.02 C268.372,46.208 268.911,46.859 269.991,46.859 L275.218,46.859 C276.262,46.859 277.126,45.956 277.126,44.875 L277.126,43.614 C277.126,42.82 276.623,42.065 275.901,41.884 L267.794,39.687 C265.236,39.001 263.47,36.407 263.47,33.597 L263.47,32.408 C263.47,28.625 266.244,25.851 270.03,25.851 L275.074,25.851 C278.567,25.851 281.414,28.445 281.847,31.83 L277.487,33.022 L277.27,32.336 C276.909,31.147 276.371,30.5 275.326,30.5 L270.102,30.5 C269.019,30.5 268.155,31.4 268.155,32.48 L268.155,33.38 C268.155,34.605 268.838,35.327 270.063,35.652 L276.804,37.379 C279.611,38.102 281.703,40.551 281.703,43.614 L281.703,44.55 C281.703,48.405 278.82,51.505 274.965,51.505 L270.244,51.505 C266.714,51.505 263.831,48.911 263.401,45.486",
    fill: "#000000"
  }), /*#__PURE__*/React.createElement("path", {
    d: "M298.432,30.5 L291.586,30.5 L291.586,25.851 L310,25.851 L310,30.5 L303.118,30.5 L303.118,51.505 L298.432,51.505 L298.432,30.5",
    fill: "#000000"
  }), /*#__PURE__*/React.createElement("path", {
    d: "M24.987,73.734 L19.819,74.926 L19.819,76.114 L24.987,77.303 L54.588,77.303 L59.756,76.114 L59.756,74.926 L54.588,73.734 L24.987,73.734 z M7.03,27.739 L3.274,27.775 L2.903,28.855 L5.914,31.124 L31.531,39.674 L35.288,39.638 L35.662,38.522 L32.648,36.253 L7.03,27.739 z M3.868,36.404 L1.228,32.089 L0,32.46 L0.41,37.556 L9.558,65.778 L12.05,70.053 L13.275,69.646 L12.868,64.327 L3.868,36.404 z M78.347,32.089 L75.707,36.404 L66.707,64.327 L66.3,69.646 L67.525,70.053 L70.017,65.778 L79.165,37.556 L79.572,32.46 L78.347,32.089 z M8.255,22.2 L32.241,4.873 L35.586,1.08 L34.805,-0 L30.119,2.009 L6.212,19.336 L2.827,23.313 L3.533,24.281 L8.255,22.2 z M71.32,22.2 L76.042,24.281 L76.748,23.313 L73.363,19.336 L49.456,2.009 L44.77,-0 L43.989,1.08 L47.335,4.873 L71.32,22.2 z M36.887,48.188 L37.855,44.882 L36.479,43.838 L33.541,45.811 L17.59,67.561 L16.437,71.169 L17.813,72.21 L20.899,70.017 L36.887,48.188 z M48.041,39.674 L73.662,31.124 L76.673,28.855 L76.302,27.775 L72.545,27.739 L46.928,36.253 L43.913,38.522 L44.288,39.638 L48.041,39.674 z M46.034,45.811 L43.096,43.838 L41.72,44.882 L42.689,48.188 L58.676,70.017 L61.762,72.21 L63.138,71.169 L61.986,67.561 L46.034,45.811 z M38.896,36.328 L38.003,32.723 L38.003,5.69 L38.896,2.082 L40.679,2.082 L41.572,5.69 L41.572,32.723 L40.679,36.328 L38.896,36.328",
    fill: "#000000"
  }))));
};
var ForwardRef = /*#__PURE__*/forwardRef(SvgLogo);
export { ForwardRef as ReactComponent };
export default __webpack_public_path__ + "logo.8f643a94aabfcf565a9b934459ac7b98.svg";

so it appears that the generated HTML img tag is pointing to a JavaScript function ...

merobal commented 1 year ago

It works well with v15.4.5 and it's broken at 15.4.6 and above (still with 15.5.3).

DanielSchiavini commented 1 year ago

I recently upgraded to 15.5.3 and now some png images from a library projected aren't loading anymore. For example, one has src="data:image/png;base64,ZXhwb3J0IGRlZmF1bHQgX193ZWJwYWNrX3B1YmxpY19wYXRoX18gKyAic3BsYXNoLWltYWdlLnBuZyI7" which after decoding means export default __webpack_public_path__ + \"splash-image.png\";

asherccohen commented 1 year ago

Confirm it's still an issue for 15.5.2

canyavall commented 1 year ago

Same here, any updates?

DanielSchiavini commented 1 year ago

There's a working workaround in https://github.com/nrwl/nx/issues/14532

asherccohen commented 1 year ago

the workaround doesn't work for me, I get undefined for the imported SVG. It fixes images, but not svgs.

martinmosko commented 1 year ago

@asherccohen This is getting a bit wild, but possible to fix it with another extension to webpack.config ๐Ÿ™ˆ Hopefully NX guys will fix it soon ๐Ÿ™

How to import svgs

https://nx.dev/recipes/other/adding-assets-react#adding-svgs

Workaround for images & svgs

const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');

// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config) => {
  // Update the webpack config as needed here.
  // e.g. `config.plugins.push(new MyPlugin())`

  config.module.rules = config.module.rules.map((rule) => {
    if (/file-loader/.test(rule.loader)) {
      return {
        ...rule,
        test: /\.(eot|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, // Excluding `svg` 
        type: "javascript/auto", // Fixing images
      };
    }

    return rule;
  });

  // This will properly handle imported svg's
  config.module.rules.push({
    test: /\.svg$/,
    use: ['@svgr/webpack', 'url-loader']
  }); 

  return config;
});
asherccohen commented 1 year ago

Your awesome, thanks!

Just a note, I had to change it a bit, this is what works for me:

const { merge } = require("webpack-merge");
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");

module.exports = (config, context) => {
  // eslint-disable-next-line no-console
  console.log("๐Ÿš€ ~ Loading Custom Webpack");

  config.module.rules = config.module.rules.map((rule) => {
    if (/file-loader/.test(rule.loader)) {
      return {
        ...rule,
        test: /\.(eot|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, //Have to remove svg from here
        type: "javascript/auto", // This is fixing issue https://webpack.js.org/guides/asset-modules/
      };
    }

    return rule;
  });

  const newConfig = merge(config, {
    module: {
      rules: [
        {
          test: /\.svg$/,
          use: ["@svgr/webpack", "url-loader"],
          type: "javascript/auto",
        },
      ],
    },
    resolve: {
      fallback: {
        fs: false,
      },
    },
    plugins: [new NodePolyfillPlugin()],
    node: {
      global: true,
    },
  });

  return newConfig;
};
vadimka123 commented 1 year ago

In case of withReact and last nx version workaround

const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');

// Nx plugins for webpack to build config object from Nx options and context.
module.exports = composePlugins(
  withNx(),
  withReact(),
  (config) => {
    // https://github.com/nrwl/nx/issues/14378

    config.module.rules = config.module.rules.map((rule) => {
      if (/file-loader/.test(rule.loader)) {
        return {
          ...rule,
          test: /\.(eot|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, // Excluding `svg`
          type: "javascript/auto", // Fixing images
        };
      }

      if (rule.test && rule.test.test('.svg')) {
        return {
          ...rule,
          use: ['@svgr/webpack', 'url-loader']
        }
      }

      return rule;
    });

    return config;
  },
);
janeklb commented 1 year ago

For anyone using TypeScript and / or wanting a cleaner plugin-based fix, here's something that worked for me:

const withSvgFix: () => NxWebpackPlugin = () => (config) => {
  config.module?.rules?.forEach((rule) => {
    if (typeof rule === 'string') {
      return;
    }

    if (typeof rule.loader !== 'undefined' && /file-loader/.test(rule.loader)) {
      rule.test = /\.(eot|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/; // Excluding `svg`
      rule.type = 'javascript/auto'; // Fixing images
    }

    if (rule.test instanceof RegExp && rule.test.test('.svg')) {
      rule.use = ['@svgr/webpack', 'url-loader'];
    }
  });
  return config;
};

// to be used with `composePlugins` 
// eg.
composePlugins(withNx(), withReact(), withSvgFix(), (config) => {
  // etc.
  return config;
});
slavoroi commented 1 year ago

Waiting for a fix to upgrade :) Version 15.4.5 works. Still an issue with 15.6.3 and 15.7.2.

Waiting for a solution as it's a breaking change for react users.

sancelot commented 1 year ago

working solution with nx 15.6.3 , react and webpack,

webpack.config.js

const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');

// Nx plugins for webpack.
module.exports = composePlugins(
  withNx({
    nx: {
      svgr: true,
    },
  }),
  withReact({ svgr: true }),
  (config) => {
    return config;
  }
);

usage :

import Logo from '-!@svgr/webpack!./assets/images/applepay.svg';
export default Logo;
import Logo from '@github-test/shared/assets';
export const ApplePayIcon = () => {
  return <Logo />;
};

refs https://stackoverflow.com/questions/75380788/nx-react-assets-cant-be-resolved/75385066#75385066

rathpc commented 1 year ago

I would say that this could be a workaround but I would hardly call it a solution to this problem. The massive changes that happened in 15.4.6 are sadly breaking and should never have been introduced as a patch version upgrade.

Can we please get a proper fix for this in a new release?

slavoroi commented 1 year ago

### Works again in 15.8.5.

A custom webpack example (lint is something we wanted to add):

const ESLintPlugin = require('eslint-webpack-plugin');
const { withReact } = require('@nrwl/react');

const { composePlugins, withNx } = require('@nrwl/webpack');

module.exports = composePlugins(
  withNx(),
  withReact(),
  (config, { options, context }) => {
    config.plugins.push(new ESLintPlugin());
    return config;
  }
);
JulioC commented 1 year ago

It looks like SVGs are working now with 15.8.5, but importing .css files from .tsx files are still causing compilation issues.

The workaround I've been using is similar to the one described earlier for .svg files:

// Based on https://github.com/nrwl/nx/issues/14378#issuecomment-1417523527
const withCssFix: () => NxWebpackPlugin = () => (config) => {
  let found = false;
  config.module?.rules?.forEach((rule) => {
    if (typeof rule === 'string') {
      return;
    }
    if (rule.test instanceof RegExp && rule.test.test('.css')) {
      if (found) {
        rule.test = () => false;
      }

      found = true;
    }
  });
  return config;
};

export default composePlugins(
  withNx(),
  withReact(),
  withCssFix()
);
ToxicToast commented 1 year ago

Its not fixed for me. After Loading SVG's from a Blob, i've got following Error Message: "error on line 1 at column 1: Document is empty"

It worked on Version 15.4.5

My Old Webpack Config:

const { merge } = require('webpack-merge');

module.exports = (config) => {
  return merge(config, {
    module: {
      rules: [
        {
          oneOf: [
            {
              test: /\.svg$/,
              type: 'asset/resource',
              generator: {
                filename: 'assets/skidfluss/[name].[hash:8].[ext]',
              },
            },
            {
              test: /\.svg$/,
              type: 'asset/resource',
              generator: {
                filename: 'assets/svg/[name].[hash:8].[ext]',
              },
            },
          ],
        },
      ],
    },
  });
};
xiongemi commented 1 year ago

i could no longer replicate this issue with @nx/react@16, @nx/webpack@16, webpack@5.75.0. closing this issue for now.

github-actions[bot] commented 1 year ago

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.