Loading SVGs within .scss with Webpack and svgr loader - javascript

Webpack config:
For a .svg I use config:{ test: /\.svg$/, use: ['svgr/webpack'] }
For .scss I use css-loader, postcss-loader and sass-loader
Folder structure:
I have folder structure that looks like this:
- App
-- styles
--- globals.scss // Here I import my partials
--- partials
---- _my_partial.scss
-- icons
--- svgs
---- my_icon.svg
svgr loader:
I like svgr loader as it allows me to just import my icon and use it as React component:
import MyIcon from './icons/svgs/my_icon.svg';
...
<MyIcon />
The actual problem:
I was fine with this approach but I have to get one of the svgs as a background-image, so inside _my_partial.scss I wrote:
background-image: url(../icons/svgs/my_icon.svg);
I am up just one folder in this url as when being up two, it complained that it cannot resolve it - I guess this is because I import my partials in my globals.scss.
With this setup all I get in the browser is:
GET http://localhost:3005/[object%20Module] 404 (Not Found)

svgr/webpack turns your svg into react components, so when using svg into scss it's actually an object / react component. Change svgr/webpack to file-loader in order to use that. If you want to still use both, you could try something like:
{ test: /\.react.svg$/, use: ['svgr/webpack'] }
{ test: /\.svg$/, use: ['file-loader'] }
then rename all the svg's that you want as React components to filename.react.svg and the rest just leave with .svg.
I haven't tested this though :)
UPDATE: Looking at the documentation (section: Handle SVG in CSS, Sass or Less), it seems you can use svgr/webpack with file-loader:
https://github.com/smooth-code/svgr/tree/master/packages/webpack
{
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
issuer: {
test: /\.jsx?$/
},
use: ['babel-loader', '#svgr/webpack', 'url-loader']
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader'
},
}
Either way, you probably need to make a few changes to fit in your needs but it supports it :)

Related

CSS into JS using webpack

I`m trying to paste a CSS Code into a JS File using webpack
My flux is the following
SASS file > CSS content > PostCSS > css file
{
test: /\.(sass|scss)$/,
exclude: /node_modules/,
use: [
MiniCSSExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
sassOptions: {
outputStyle: 'compressed'
}
}
}
]
}
But the MiniCSSExtractPlugin gets me the content into a css file.
I'm use Lit Element so the styles should be declare with css function part of lit-element on the following way
import {css} from 'lit-element';
export default css`
:host {
display: inline;
}
`;
Is there any way to generate css code as a string and paste it into js file?
To import a CSS file into JS (w/webpack) you need to configure webpack with the following loaders:
css-loader
style-loader
Both available with NPM:
$ npm i css-loader style-loader --save-dev
And add this entry to the module.rules array in your webpack configuration:
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
The result
Both of this loaders correctly configured will allow you to do the following sentence in JavaScript:
import myStyles from './your-css-file.css';
And then, you can just paste them into literal templates as follows:
static get styles() {
return css`${myStyles}`;
}
Additionally:
With a deep knowledge into what you might be talking about, you might need to take a look around #cells/cells-cli files and add those loaders into webpack configuration. Otherwise, you may need to create a webpack.config.js file in every lit-element component, which might not be the best for the current architecture.
Nice to see you around here, ¡saludos!;)
#k3llydev, I tried your suggestion and couldn't get it to work. Do you have any suggestions, specifically when you say "both of these loaders correctly configured will allow you to do the following"? I'd like to be able to import the CSS and then use it directly in the styles getter like you show in your example, but I had to do this as a workaround:
import MyImportedStyle from './some.css';
static get styles () {
return [
css`${unsafeCSS(MyImportedStyle.toString())}`
];
}
While using the 'to-string-loader' in webpack:
{
test: /\.css$/i,
use: ['to-string-loader', 'css-loader'],
}
This worked out for me and did what I wanted, but if I could avoid using the to-string-loader and could use the imported object directly, that would be idea. Any suggestions?
This way should do what the original poster asked for, a way to get the CSS as a string and use it in your LitElement.

vueJS + webpack: importing fonts, CSS, and node_modules

I'm starting with Vue.js and Webpack and I'm having some doubts about how to correctly import and reference my fonts, CSS, and node_modules correctly.
I started my application using vue-cli, and here's the resultant structure:
build
config
node_modules
src
--assets
--components
--router
static
And here's my webpack.base.conf file:
var path = require('path')
var utils = require('./utils')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': resolve('src')
}
},
module: {
rules: [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
}
}
First of all, where is the correct place to put my custom CSS and images? I'm currently putting them inside assets/css and assets/img, respectively (I created these folders). Is it correct?
I also have some CSS and fonts from external libraries (Bootstrap and Font Awesome, for example) that I have installed via NPM. They're located at node_modules.
If I'm not wrong, Webpack transforms, and copies these files to another location. How can I reference them on my Vue files and CSS files?
Using import './assets/css/style.css'import '../node_modules/path/to/bootstrap.min.css' works (at least in production), but should I be using another path?
Inside my custom CSS files, I reference some fonts from an external library using:
src: url('/node_modules/roboto-fontface/fonts/Roboto/Roboto-LightItalic.eot')
The code compiles, but when I open the page in the browser, I receive a 404 error when searching for these fonts. How should I be referencing these fonts in my custom CSS?
First of all, where is the correct place to put my custom css and images? I'm currently putting them inside assets/css and assets/img, respectively (I created these folders). Is it correct?
This is kind of a subjective question, but the short answer is yes.
The cli tool already created this for you, defined some stuff in the Webpack config files, so why not use it?
Using import './assets/css/style.css'import '../node_modules/path/to/bootstrap.min.css' works (at least in production), but should I be using another path?
Webpack embeds the css into the it's JS file, so if you don't import it Webpack will not know about it.
Here is an example with loading images dynamically
<ul id="albums">
<li v-for="album in albums">
<img :src="LoadImage(album.data.imagefile)" />
</li>
</ul>
if you'll just hand the src binding the artwork file it will fail to load it, so we hand the image file name to a method that goes like this
LoadImage(filename) {
const image = require('#/assets/img/' + filename)
return image
}
now inside the method we load the image from the assets folder ( using the # notation that was configured in the webpack.base.conf file under resolve.alias )
So yes, using the import/require functions are the way to go for Webpack to get to know your files.
Inside my custom css files, I reference some fonts from an external library using:
src: url('/node_modules/roboto-fontface/fonts/Roboto/Roboto-LightItalic.eot')
The code compiles, but when I open the page in the browser, I recieve a 404 Error when searching for these fonts. How should I be referencing these fonts on my custom css?
It's best that you'll copy everything you want in your dist folder in your src folder. I'm not really sure, never tried it, but looking at the webpack.prod.conf file it looks like it will only copy files from the src/assets folder.
Regarding the font not loading, this is a bit different since the url-loader will handle the files, so you have to think of it from the browser point of view, and reference it like a url path.
here is an something i have in one of my components
#font-face {
font-family: BebasNeue;
src: url('./assets/fonts/BebasNeue.otf');
}
See how i didn't used the # notation to reference it from the src folder? no need for urls.
I'm guessing you already answered this question and if not, Hope that helps!
You can ask questions here http://chat.vuejs.org/ and get answers from the community and the core team.
Quck solution
what i did comment #font-face {} section and build and added custom css to style file

How to import a CSS file in a React Component

I want to import a CSS file into a react component.
I've tried import disabledLink from "../../../public/styles/disabledLink"; but I get the error below;
Module not found: Error: Cannot resolve 'file' or 'directory' ../../../public/styles/disabledLink in c:\Users\User\Documents\pizza-app\client\src\components # ./client/src/components/ShoppingCartLink.js 19:20-66 Hash: 2d281bb98fe0a961f7c4 Version: webpack 1.13.2
C:\Users\User\Documents\pizza-app\client\public\styles\disabledLink.css is the location of the CSS file I'm trying to load.
To me it seems like import is not looking up the correct path.
I thought with ../../../ it would start to look up the path three folder layers above.
C:\Users\User\Documents\pizza-app\client\src\components\ShoppingCartLink.js is the location of the file that should import the CSS file.
What am I doing wrong and how can I fix it?
You don't even have to name it if you don't need to:
e.g.
import React from 'react';
import './App.css';
see a complete example here (Build a JSX Live Compiler as a React Component).
You need to use css-loader when creating bundle with webpack.
Install it:
npm install css-loader --save-dev
And add it to loaders in your webpack configs:
module.exports = {
module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" },
// ...
]
}
};
After this, you will be able to include css files in js.
I would suggest using CSS Modules:
React
import React from 'react';
import styles from './table.css';
export default class Table extends React.Component {
render () {
return <div className={styles.table}>
<div className={styles.row}>
<div className={styles.cell}>A0</div>
<div className={styles.cell}>B0</div>
</div>
</div>;
}
}
Rendering the Component:
<div class="table__table___32osj">
<div class="table__row___2w27N">
<div class="table__cell___2w27N">A0</div>
<div class="table__cell___1oVw5">B0</div>
</div>
</div>
The following imports an external CSS file in a React component and outputs the CSS rules in the <head /> of the website.
Install Style Loader and CSS Loader:
npm install --save-dev style-loader
npm install --save-dev css-loader
In webpack.config.js:
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
}
In a component file:
import './path/to/file.css';
CSS Modules let you use the same CSS class name in different files without worrying about naming clashes.
Button.module.css
.error {
background-color: red;
}
another-stylesheet.css
.error {
color: red;
}
Button.js
import React, { Component } from 'react';
import styles from './Button.module.css'; // Import css modules stylesheet as styles
import './another-stylesheet.css'; // Import regular stylesheet
class Button extends Component {
render() {
// reference as a js object
return <button className={styles.error}>Error Button</button>;
}
}
The solutions above are completely changed and deprecated. If you want to use CSS modules (assuming you imported css-loaders) and I have been trying to find an answer for this for such a long time and finally did. The default webpack loader is quite different in the new version.
In your webpack, you need to find a part starting with cssRegex and replace it with this;
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
modules: true,
localIdentName: '[name]__[local]__[hash:base64:5]'
}),
}
You can import css file if css file reside in a same folder where you want to import than just simple try this
import './styles.css'
if css file is far away from our component that navigate that place where file is reside and use this like
import '../mainstyles/styles.css'
In cases where you just want to inject some styles from a stylesheet into a component without bundling in the whole stylesheet I recommend https://github.com/glortho/styled-import. For example:
const btnStyle = styledImport.react('../App.css', '.button')
// btnStyle is now { color: 'blue' } or whatever other rules you have in `.button`.
NOTE: I am the author of this lib, and I built it for cases where mass imports of styles and CSS modules are not the best or most viable solution.
You can also use the required module.
require('./componentName.css');
const React = require('react');
Install Style Loader and CSS Loader:
npm install --save-dev style-loader
npm install --save-dev css-loader
Configure webpack
module: {
loaders: [
{
test: /\.css$/,
loader: 'style-loader'
}, {
test: /\.css$/,
loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
}
]
}
Using extract-css-chunks-webpack-plugin and css-loader loader work for me, see below:
webpack.config.js Import extract-css-chunks-webpack-plugin
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
webpack.config.js Add the css rule,
Extract css Chunks first then the css loader css-loader will embed them into
the html document, ensure css-loader and extract-css-chunks-webpack-plugin are in the package.json dev dependencies
rules: [
{
test: /\.css$/,
use: [
{
loader: ExtractCssChunks.loader,
},
'css-loader',
],
}
]
webpack.config.js Make instance of the plugin
plugins: [
new ExtractCssChunks({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: '[name].css',
chunkFilename: '[id].css'
})
]
And now importing css is possible
And now in a tsx file like index.tsx i can use import like this
import './Tree.css' where Tree.css contains css rules like
body {
background: red;
}
My app is using typescript and this works for me, check my repo for the source :
https://github.com/nickjohngray/staticbackeditor
You can import your .css file in .jsx file
Here is an example -
import Content from '../content/content.jsx';

Webpack not loading SCSS with react-toolbox

I am trying to bootstrap a new react app and use the react-toolbox library and webpack. I am unable to get both react-toolbox's styles and my own app's styles to load.
The way I'm used to importing scss files is from the react files/views/components they go with, so they are located in the same folder. So if I have a react component file called header.js, in the same directory there is header.scss. Header.js calls import './header.scss'. In webpack, what I previously used to load scss was:
{
test: /\.s?css$/i,
loader: 'style!css!sass?' +
'includePaths[]=' + (path.resolve(__dirname, './node_modules')),
},
But when I include react-toolbox, this setup completely excludes react-toolbox's styles. I found this issue https://github.com/react-toolbox/react-toolbox/issues/121 where mattgi recommends this webpack-config:
{
test : /(\.scss|\.css)$/,
include : path.join(__dirname, '../../', 'src'),
loaders : [ 'style', 'css', 'sass' ]
},
{
test : /(\.scss|\.css)$/,
include : /(node_modules)\/react-toolbox/,
loaders : [
require.resolve('style-loader'),
require.resolve('css-loader') + '?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
require.resolve('sass-loader') + '?sourceMap',
]
},
This resolves the react-toolbox styles not loading, but then when I try to import my own scss files in a js file, webpack throws this error for the scss file: You may need an appropriate loader to handle this file type. (I have sass-loader installed).
In addition, if I include the scss file in the same directory with the same name (some-react-class.js and some-react-class.scss), the containing component of SomeReactClass that is importing some-react-class.js imports it as an object instead of a function which makes it seem like it is importing the scss instead of the js.
Help :(
Try to omit "include" property like this:
{
test: /(\.css|\.scss)$/,
loader: 'style!css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass?sourceMap'
}
This loader should include your *.scss and those from react-toolbox.
Seems hacky - but I did this to get it to work:
{
test: /\.s?css$/,
loaders: ['style', 'css', 'sass'],
exclude: /(node_modules)\/react-toolbox/
},
{
test : /(\.scss|\.css)$/,
include : /(node_modules)\/react-toolbox/,
loaders : [
require.resolve('style-loader'),
require.resolve('css-loader') + '?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
require.resolve('sass-loader') + '?sourceMap'
]
},
Bootstrap styles and react-toolbox styles work - but I'm having a hell of a time adding a file to override the default sass variables via toolbox-loader. Not sure if the issue is related to this hackiness...ugh headache

React is expected to be globally available

I'm playing with React (#13.3) with babel and webpack.
I have a component that's defined like this:
import BaseComponent from './BaseComponent';
export default class SomeComponent extends BaseComponent {
render() {
return (
<div>
<img src="http://placekitten.com/g/900/600"/>
</div>
);
}
}
But I get the following error:
Uncaught ReferenceError: React is not defined
I understand the error: the JSX bit is compiled into React.createElement(...) but React isn't in the current scope since it's not imported.
My questions is:
What's the clean way to work around this issue? Do I have to somehow expose React globally with webpack?
Solution used:
I followed #salehen-rahman suggestion.
In my webpack.config.js:
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'react-hot!babel?plugins[]=react-require'
}, {
test: /\.css$/,
loader: 'style!css!autoprefixer?browsers=last 2 versions'
}]
},
I also needed to fix my tests, so I added this to the file helper.js:
require('babel-core/register')({
ignore: /node_modules/,
plugins: ['react-require'],
extensions: ['.js']
});
My tests are then launched with the following command:
mocha --require ./test/helper.js 'test/**/*.js'
My questions is : What's the clean way to work around this issue ? Do I have to somehow expose React globally with webpack ?
Add babel-plugin-react-require to your project, and then amend your webpack's Babel config to have settings akin to:
loaders: [
{
test: /.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
stage: 0,
optional: ['runtime'],
plugins: [
'react-require' // <-- THIS IS YOUR AMENDMENT
]
},
}
]
Now, once you've applied the configuration update, you can initialize React components without manually importing React.
React.render(
<div>Yippee! No <code>import React</code>!</div>,
document.body // <-- Only for demonstration! Do not use document.body!
);
Bear in mind though, babel-plugin-react-require transforms your code to automatically include React imports only in the presence of JSX tag in a specific file, for a specific file. For every other file that don't use JSX, but needs React for whatever reason, you will have to manually import React.
If you have react in your node modules directory you can add import React from 'react'; at the top of your file.
You can use Webpack's ProvidePlugin. To use, update the plugins section in your Webpack config to include the following:
plugins: [
new webpack.ProvidePlugin({
'React': 'react'
})
]
This, however, doesn't solve it for the tests..

Categories

Resources