I'm stuck with the loading image, I've been searched all the sources, and i don't find any answer of this. The code below it doesn't works
import goldImage from './../../../public/img/gold.png';
but when i'm write like this, it works:
const gold = '../../../public/img/gold.png';
Or if I'm importing the JPG file, it works:
import test from './../../../public/img/kaslie.jpg';
I'm also using Webpack 2, here is my code:
test: /\.(png|jpe?g|gif|svg)$/,
use:[
{
loader: 'url-loader',
options:{limit:40000,name:'[path][name].[ext]?[hash]'}
},
'image-webpack-loader?bypassOnDebug&optimizationLevel=7&interlaced=false'
]
I don't have any idea for this, why its only work for jpg file, but PNG file not work.
For images you should use:
const goldImage = require('./../../../public/img/gold.png');
<image src{goldImage} alt="" />
The import statement is used to import functions, objects or primitives that have been exported from an external module, another script, etc.
Related
Is it possible to conditionally import assets when creating a React app using create-react-app? I'm aware of the require syntax - example:
import React from "react";
const path = process.env.REACT_APP_TYPE === "app_1" ? "app_1" : "app_2";
const imagePath = require(`./assets/${path}/main.png`);
export default function Test() {
return (
<img src={imagePath} alt="" />
);
}
This however bundles all my assets no matter what.
It will load the proper image, but it will still bundle all the files together in the final build.
When I look in the dev tools for the final build, I can see all the assets there even though I only wanted to load the assets for app_1.
Am I forced to touch the webpack config, if so, what should I change? or is there another way?
In the days when React didn't exist we didn't put assets into our JS files. We let the CSS to decide, what assets to load for what selectors. Then you could simply switch a corresponding class on or off for a corresponding element (or even the whole page) and viola it changes color, background, or even a form. Pure magic!
Ah. What times these were!
All above is true and I do not understand why would anyone do or recommend doing it differently. However if you still want to do it (for any reason) - you can! Latest create-react-app comes with out-of-the-box support for lazy loading of arbitrary components via dynamic importing and code splitting. All you need to do is use parenthesized version of the import() statement instead of the regular one. import() takes in a request string as usual and returns a Promise. That's it. Source code of the dynamicaly requested component won't be bundled in, but instead stored in separate chunks to be loaded on demand.
Before:
import OtherComponent from './OtherComponent';
function MyComponent() {
return (
<div>
<OtherComponent />
</div>
);
}
After:
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<OtherComponent />
</div>
);
}
Notice how function MyComponent part is identical.
For those wondering if it is tied to CRA or React, it's not. It's a generic concept that can be used in vanilla JavaScript.
You will need to use webpack (or other bundler.) The code is not being run when it's bundled, so the compiler has no way of knowing which branch of logic to follow (app_1 or app_2). Therefore you have to get into the bundler's logic in order to achieve your goal.
However, this isn't as scary as it seems since webpack has built in capability to do this (no 3rd parties required...)
I would look into using webpack.providePlugin
(https://webpack.js.org/plugins/provide-plugin)
or its sibling DefinePlugin
(https://webpack.js.org/plugins/define-plugin)
(I'm afraid these examples are off the top of my head, so it's very unlikely they'll work on first pass.)
Examples:
Both will require a provider module...
// in path/provider.js
module.exports = {
live: '/path/to/live/image',
dev: '/path/to/dev/image'
}
Provide Plugin Example
// in webpack
new webpack.ProvidePlugin({
imagePath: [
'path/provider', // the file defined above
process.env.ENVIRONMENT // either 'dev' or 'live'
]
}),
// in code
export default function Test() {
return (
<img src={imagePath} alt="" />
);
}
Define Plugin example:
// in webpack
new webpack.DefinePlugin({
'process.env.ENVIRONMENT': JSON.stringify(process.env.ENVIRONMENT)
});
// in code
var providers = require('path/provider'); // same path provider as above
export default function Test() {
return (
<img src={providers[process.env.ENVIRONMENT]} alt="" />
);
}
In both cases the bundler is forced to collapse your variable to an actual literal value at compile time - before bundling has taken place. Since you have now collapsed the logical path down to a single option, it is now free to only bundle the relevant assets.
You can't do this with default CRA settings.
Because if your dynamic require or dynamic import path is not static, webpack won't be able to determine which assets to include in the final build folder, therefore, it will grab everything from your ./src folder, and put them all to your build folder.
There is a way to do it with default CRA settings
You can add to .env something like
REACT_APP_SKIN=1
Put your skin assets in public/css1, public/css2 etc. And include them in public/index.html using code like
<link href="/css%REACT_APP_SKIN%/theme.css" rel="stylesheet">
I would like to have a loader that collects all css sources and allows me to get all contents in a function. Like this:
Webpack config
module: {
loaders: [
{test: /\.css$/, loader: 'my-loader'}
]
}
JS file A (foo.js)
import './foo.css';
JS file B (bar.js)
import './bar.css';
JS file C (app.js)
import './app.css';
import getAllCSSContents from 'my-loader';
const css = getAllCSSContents();
where getAllCSSContents would return all CSS contents from foo.css, bar.css and app.css
This is a bit tricky because the loader you want to make needs to know about all CSS modules before it can generate the code it needs to return, making it stateful (loaders are meant to be pure functions that transform one input module).
You can kind of achieve what you want using raw-loader and require.context like this:
// Load all CSS files in the current directory and descendants
const context = require.context('!raw-loader!./', true, /\.css$/);
const cssFiles = {};
for (let filename of context.keys()) {
cssFiles[filename] = context(filename);
}
I have
Tutorial.jsx
class ShoppingList extends React.Component {
render() {
return (<div>Milk</div>);
}
}
export default ShoppingList;
webpack.config.js
module.exports = {
...
output: './React/bundle.js',
...,
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: "babel-loader",
query: {
presets: ['es2015', 'react'],
}
}
]
}
}
In my CMD prompt, when I run webpack -w everything is green and I see my bundle.js file appearing where it should, in the React folder. Opening it, I see
...
var ShoppingList = function (_React$Component) {
...
}
...
so it looks like that's all good.
Now I want to render ShoppingList in my _Layout.cshtml file.
Question: How do I do this? I've tried all methods below and get React errors all the time about invalid parameter type, or passing in the wrong element, or whatever. My CSHTML is below.
<div id="content1">render here</div>
....
<script src="~/React/bundle.js"></script>
<script>
ReactDOM.render("ShoppingList", document.getElementById("content1"));
ReactDOM.render(ShoppingList, document.getElementById("content1"));
ReactDOM.render(<ShoppingList />, document.getElementById("content1"));
</script>
Can someone please let me know if
It's possible to NOT have a ReactDOM.render() inside the JSX file and,
It's possible to do what I want to do which is render my ShoppingList in CSHTML
The best results I've got so far is to see ShoppingList in my DOM explorer but no HTML was actually rendered. It came out <shoppinglist ...></shoppinglist> which appears wrong to me.
Thanks.
You should have this inside your entry file:
import ShoppingList from 'path-to/ShoppingList';
ReactDOM.render(<ShoppingList />, document.getElementById("content1"));
In the CSHTML page the additional script tag is not required.
Your original example does not work because:
ShoppingList is not exposed globally (exporting as default does not make it global).
JSX syntax (<ShoppingList />) needs to be transpiled before it can be used in HTML page.
If you really need to use a component within a CSHTML page, you can make the component global:
window.ShoppingList = ShoppingList
inside the file that defines the component.
And use vanilla javascript instead of JSX syntax:
ReactDOM.render(React.createElement(ShoppingList), document.getElementById("content1"))
I have 100's of Icons and Images to be imported. Is there any way to eliminate writing so many import statements at the top of the page? I was thinking to write a import statements in a separate file and embed that at the top.
import basicAmenitiesIcon from '../../../../images/icons/wifi-sign.png';
import parkingIcon from '../../../../images/icons/parking.png';
...
Any other way of solving it? I'm using webpack and here is the config:
{
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: [
'file?hash=sha512&digest=hex&name=[hash].[ext]',
'image-webpack?bypassOnDebug&optimizationLevel=7&interlaced=false'
]
}
Yes, it is posible, see my answer here: https://stackoverflow.com/a/41410938/646156
var context = require.context('../../../../images/icons', true, /\.(png)$/);
var files={};
context.keys().forEach((filename)=>{
files[filename] = context(filename);
});
console.log(files); //you have file contents in the 'files' object, with filenames as keys
I'd like to declare my styles (stylus) inside of my React component classes as such. Preferably while also utilizing CSS modules:
export default class HelloWorld extends Component {
render() {
return (
<div className={styles.hello} />
);
}
static styles = `
.hello
display block
`;
}
or even perhaps
const styles = stylus`
.hello
display block
`;
const HelloWorld = () => <div className={styles.hello} />
The goal here is to compile the styles into a stylesheet via stylus (or another preprocessor), strip the style block from the resulting javascript bundle, and access styles through CSS modules and the className property in JSX. I'd prefer to have these compiled at compile time (babel/webpack) rather than at runtime.
I'm not necessarily looking for hard and fast code, but any direction would be greatly appreciated. I'm not sure if all of this is even possible, although some of it definitely should be. I understand that accessing styles via styles. may not be feasible.
I've never written a babel or webpack plugin so I barely know where to start. Most of the documentation and tutorials that I read didn't seem to get me where I wanted to go.
Thanks
What you're trying to do is not possible, but there is a workaround; unfortunately, the answer might taste like bathtub gin. As you are probably aware, you cannot directly require Stylus. Accordingly, your forced to use a Stylus loader which you have two options, stylus-loader or Walmarts stylus-relative-loader, I would recommend the latter. Here is where things get a bit convoluted. Since you want to use CSS modules and compile the styles into a stylesheet, you will have to use the extract-text-webpack-plugin.
Long story short, if you are using Webpack 1.x here's an example configuration of the loader which you will need to implement into your Webpack config, which uses extract-text-webpack-plugin, css-modules, and stylus-relative-loader.
module: {
loaders: [{
test: /\.styl$/,
loader: ExtractTextPlugin.extract('style-loader', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!stylus-relative-loader')
}]
},
plugins: [
new ExtractTextPlugin('main.css')
]
From here all you need to do is move your Stylus to a separate file like my-styles.styl and then require it into your React component like so.
const styles = require('./my-styles.styl')
const HelloWorld = () => <div className={styles.hello} />
PS. Sorry, if this is not what you're looking for but my "reputation" does not allow me to ask questions via comments nor can I use more than two links.