Unable to find svgs assets with Parcel in React and TS - javascript

I've added parcel to a create-react-app project that uses the typescript template. I'm trying to add svgs to my outputted js file following the recommendations from their docs. I'm not sure if there's something that has to be done differently in TS, but I set up my project as they suggested as their JSX snippets and it didn't work:
.parcelrc
{
"extends": "#parcel/config-default",
"transformers": {
"jsx:*.svg": ["...", "#parcel/transformer-svg-react"]
}
}
Note: I've added the transformer plugin to my dev deps.
Component.tsx
import BriefcaseSvg from "jsx:../../assets/briefcase.svg";
// ...later in my return statement:
<img src={BriefcaseSvg} alt="work icon" />
// I've also tried
<BriefcaseSvg/>
Every time I get the following error:
Cannot resolve dependency 'jsx:../../assets/briefcase.svg'
I've also tried converting both jsx declarations to tsx.
I've added parcel on top of the standard webpack build tool you get with CRA. Wepback has no problem and displays the icon just find. Parcel also was able to run a build when I didn't include this svg plugin but outputted the svg separately in its own file.
I'd like everything to end up in one js file. How can I achieve this with parcel, react, and TS?

The default parcel config defines an svg transformer and optimizer, which are not properly resolving imports. You can follow the issue on GitHub at https://github.com/parcel-bundler/parcel/issues/7587.
As a workaround (for any type of import), you do not need to import a transformer.
Replace "jsx:" with "url:" in your import like this:
import BriefcaseSvg from "url:../../assets/briefcase.svg";
And use the src attribute, not a component.
<img src={BriefcaseSvg} alt="work icon" />
You can read more about the syntax at https://github.com/parcel-bundler/parcel/pull/4055. It only works in JS and was meant to support importing files that are not explicitly supported.

Related

Importing JS bundle to an Angular Library

I am trying to add a JS script bundle file to a custom Angular Library which is using features from it. I have added the types files so the linting errors are not showing, but the Project does not get built as classes from JS Bundle are not found.
I have tried and failed importing the bundle to the public-api file.
I am thinking of trying to make the bundle a private npm package to install. But that will take lot of time and effort.
What other options do I have?
Sometimes you could have that kind of circumtances like having would like to use an JS library in your Angular project.
i have encountered something like that but i have created one directive file in the src folder like "type.d.ts" so after i declared my library in it with something like "declare module 'pdfmake/build/vfs_fonts.js';" and at last imported it in my component file like "import * as pdfMake from 'pdfmake/build/pdfmake.js';"
1- Create one directive file like "type.d.ts"
2- Declare your JS library in your recent file created with something like "declare module 'pdfmake/build/pdfmake.js';"
3- Declare back the import statement in your component file like "import * as pdfMake from 'pdfmake/build/pdfmake.js';"

Running ts-node scripts that import css modules

How can I run scripts that import css modules?
I'm writing a typescript migration script that I'd like to run via ts-node. Ideally, my codebase would be organized such that the script's dependencies never touch React components, but that's not the case. The script ultimately imports React components and thus css modules, so ts-node fails because it doesn't understand css modules:
RenderableInline.tsx(4,20): error TS2307: Cannot find module './styles/RenderableInline.module.scss' or its corresponding type declarations.
Only webpack understands how to build css modules, since I've configured it via a css-loader.
The only precedent for this I've found is jest, which has some configuration option for mocking out css modules so it can import these files without error: https://jestjs.io/docs/webpack.
How can I run a typescript script that has dependencies on css modules? Is there someway to do this via ts-node? Or does webpack have some script running feature?
Add a global .d.ts file that provides direction on how .css files should be handled.
Such as src/global.d.ts with the following contents:
declare module '*.module.css' {
const classes: { [key: string]: string };
export default classes;
}
May also be helpful to add the typescript-plugin-css-modules plugin. Note though that this only helps during development using VSCode but has no effect during compilation.
While I generally got this working, I am still facing problems to get this to work correctly with ts-node-dev - probably related to ts-node not loading these type files by default Missing Types. Unfortunately even using the --files directive, I couldn't get this to work.

exporting .png files from a library to a React JavaScript project

I'm creating a utility project that will supply React components and resources to my other projects.
I'd like it to include a set of images (mostly .png files for icons) that can then be imported by the child projects.
I can't figure out how to make this work.
I can export the images from the library, and I can see them, name-mangled, in the node_modules of the child project. So, all good so far.
But, import {imgName} from "myLib" does not include the file in the child project's bundle.
It looks to me like my problem is explained by a clue in https://create-react-app.dev/docs/adding-images-fonts-and-files/:
You can import a file right in a JavaScript module. This tells
webpack to include that file in the bundle.
Presumably, CRA is not triggering this webpack behavior in my case, since I'm importing from another module, not from a file.
How can I get things working?
Assume:
I have complete ownership of the library and child projects, so I can change this solution in whatever way works. I just want to have a single common resource for the images.
I don't want to eject my child projects
Ideally, any complexity should be in the library project. The child projects should have minimal complex tooling. (My intent is for this library to be used by a team of other developers, who will want to focus on their own tasks; not on tooling details)
EDIT (ADDED LATER)
Per the comments in the first answer below, I've created a simple example of my problem. See:
Library repo: github.com/deg/media-file-bug-library
Library package: npmjs.com/package/media-file-bug-library
Client repo: github.com/deg/media-file-bug-client
Just pull the client repo and do yarn install and yarn start. This will bring up a little web page that shows the problem:
SCREEN SNAPSHOT:
The Problem is Not in CRA Trigger. Importing Png File like JavaScript Hides a Magic. Here you are importing a Image and Exporting it which then get Processed by bundler and The Bundled Index Actually Exports The name of the Processed Image File Which in Your Case is corss~nAalnlvj.png. That's Why Your Image is Broken but you are able to render name of File, The Case is Same for microbundle or parcel.
How You Can solve it is by separating your assets and components By Placing Images on separate assets folder and place your images there and then add assets to files in your files in package.json
{
.
.
"files": [ "dist", "assets"],
}
And Then Import Image & Using Like This
import React from 'react'
import ico_cross from 'media-file-bug-library-fix/assets/cross.png'
function App() {
return (
<div className="App">
<img src={ico_cross} alt="im"/>
</div>
);
}
For Further Reference Checkout
Here
A Npm Library For Your Fix I Published Npm media-file-bug-library-fix
enter image description here
hey David I found the solution please do check the above screenshot
as in you package just change in index.modern.js
// WebPack doesnt listen as a path it listen
// var cross = "cross~nAalnlvj.png";
// use import rather than simple name as it generate a full absolute path at parent level so that in child level it can be accessible as an Image
import cross from "./cross~nAalnlvj.png"

How to use tree shaking for node modules with Webpack 5?

I want to boost my website performance. I recently see an error on unused javascript from lighthouse.
I checked the bundle and apparently those unused javascript are actually being used from other modules and node packages which I have been download.
For example, #sentry/node is what I'm using, but report shows unused javascript from #sentry/hub. But I only did install on #sentry/node but not the whole #sentry package. Further more, #sentry/node is using #sentry/hub, but I'm not importing #sentry/hub anywhere in my code (which I assume that causes the problem)
I have included "sideEffects": false to my package.json file but nothing seems to work
You could try destructuring, target only the object (or function) you are using.
e.g.
import { Component } from 'react';
Therefore, for you...
import { yourFunction } from `#sentry/node`;
Or simply take the code #sentry/node that you are using. 🤷‍♂️
Otherwise, show your code:
package.json
webpack.config.js
your "index" file (where you import your scripts and other files)
the file you import #sentry/node in

Why I can not import directly from node_modules using SystemJS?

While there is a lot of questions and documentation on SystemJS, I still don't understand the import syntax.
Specifically, why can typescript not find ng-boostrap.js using this code:
import { createPlatform } from '../../node_modules/#ng-bootstrap/ng-bootstrap/bundles/ng-bootstrap',
which is directly importing the file, but this code works:
import {createPlatform } from './node_modules/#angular/core/bundles/core.umd.js';
where my map in systemjs.config.js contains the line:
'#angular/core': 'npm:#angular/core/bundles/core.umd.js'.
Why I can not import directly from node_modules using systemJS?
Note: Though the solution below works, some of the information is incorrect. Please see discussion below in comments.
First of all, TypeScript doesn't know anything about JS files. It knows how to produce them, but doesn't know how to compile against them. So I am not sure how you actually got
import {createPlatform } from './node_modules/#angular/core/bundles/core.umd.js';
to compile in your TypeScript code.
We are able to do
import {createPlatform } from '#angular/core';
in TypeScript, because TypeScript is already looking in the node_modules. And #angular/core, if you look inside your node_module, has the directory #angular/core, with an index.d.ts file. This is the file that our TypeScript code compiles against, not the JS file. The JS file (the one in the above first code snippet) is only used at runtime. TypeScript should know nothing about that file.
Using the second snippet above, when the TypeScript is compiled to JS, it looks like
var createPlatform = require('#angular/core').createPlatform;
As runtime, SystemJS see's this, then looks at the map configuration, and maps the #angular/core to the absolute file location, and is able to load that file
'#angular/core': 'npm:#angular/core/bundles/core.umd.js'
This is the pattern that you should follow with the ng-bootstrap. Use the import that points to the TypeScript definition file, so that it can compile
import { ... } from '#ng-bootstrap/ng-bootstrap';
If you look in the node_modules/#ng-bootstrap/ng-bootstrap directory, you should see the index.d.ts file. This is what TypeScript will use to compile against. When it is compiled to JS, it is compiled the following
var something = require('#ng-bootstrap/ng-bootstrap').something;
And in the SystemJS config, we need to map #ng-bootstrap/ng-bootstrap to the absolute path of the module file, otherwise SystemJS won't know how to resolve it.
'#ng-bootstrap/ng-bootstrap': 'npm:#ng-bootstrap/ng-bootstrap/bundles/ng-bootstrap.js'
One of the key take-aways from this, is to understand the difference between compile-time and runtime. Compile type is TypeScript, which doesn't know anything about JS files, as those are runtime files. SystemJS is the one that needs to know about the runtime (JS) files.

Categories