I am building something like a static website generator that uses webpack to build the project and create a bundle with it.
In this project, a user is able to specify custom css files. I want those css files to be bundled with the final result. The issue is, that I do not have the paths to those css files available during development, so I can't do import 'some-asset-file-provided-by-the-user.css' in the javascript code that is going to be bundled. But I have them available when calling webpack.compile(config).
I am looking for a way to inject those css files into the bundle. So far I tried various ways, such as:
const stylesheet = 'some-asset-file-provided-by-the-user.css'
require(stylesheet)
Which did not work, probably because webpack is not able to deal with this "dynamic" require. Then I used the webpack define plugin for this
/* webpack.config.js */
new webpack.DefinePlugin({
stylesheet: 'some-asset-file-provided-by-the-user.css'
}),
/* app.js */
require(stylesheet) // should be replaced by the webpack define plugin with 'some-asset-file-provided-by-the-user.css'
which also did not work. I also tried to find a way to do something like this:
{
test: /\.css$/,
loader: ExtractTextPlugin.extract(Object.assign({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
useFiles: ['file-a.css', 'file-b.css']
}
}
]
}, extractTextPluginOptions))
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
which also failed because apparently neither style-loader nor css-loader support this type of interaction.
How can I solve this? I am open to writing a plugin for this, but I'd rather use something existing.
The simplest way to include the CSS is by adding it to your entry point. To make this easier, you should use an array as entry point even if it's just a single file, so you can simply push the CSS.
For example:
entry: {
app: ['./src/index.js'],
// Other entries
},
In your compile script you add it to entry.app before passing it to webpack.
config.entry.app.push('./user.css');
const compiler = webpack(config);
Related
I'm developing a react UI component and it depends on another UI component (react-widgets/lib/DropDownlist). This javascript module has resources that end with these file extensions: *.gif, *.eot, *.svg, *.woff, *.ttf.
Webpack4 is complaining that it doesn't know how to process these file types and that I might need a loader to handle these file type. One error is:
Error in .../react-widgets/dist/fonts/rw-widgets.svg?v=4.1.0
Module parse failed: ...
**You may need an appropriate loader to handle this file type.**
So I need to update my webpack.config.js file with the appropriate loaders for those file types. My config is based off of this. Side Note: A
shout out goes to Mark England who wrote this article which does a fantastic job for how to create a reusable component.
The relevant snippet is:
// Snippet from Mark's code webpack.config.js
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
I know what the syntax for webpack is to define the loaders but I don't know what loaders to use. But this sample webpack config file didn't include support for these other file types.
What have I done to try and solve the problem
I generally use create-react-app so I avoid this problem altogether. :-) It, however, doesn't allow me to create react libraries for distribution (AFAIK).
First I searched on the net webpack *.gif loader. Nothing useful.
Next I searched for webpack loaders based on file type. This gave some good results that describe the loader syntax, pointed me to some loaders file-loader and how to use them, and this question on SO that helps me realize the *.svg loader might be what I need to load svg files.
{test: /\.svg$/, use: "svg-inline-loader"},
So I might be able to use svg-inline-loader for the *.svg files.
I can repeat this approach for all of the file types.
The next approach is to examine Create React App (CRA)
I primarily develop in react, and look at the CRA webpack config files (because the create-react-app appears to stay leading edge on these topic). So I can see the url-loader is used for images (based on what the node_modules/react-scripts/config/webpack.config.dev.js file is using).
Another one down...
My question
Does webpack (or another website) have a table that lists the loaders available for given file types?
For example,
know good image loaders for the following file types are:
Webpack 4
*.gif, *.jpg => url-loader
*.svg => svg-inline-loader
*.eot => ???
I realize that because webpack is more of a plugin/loader architecture that it might not be webpacks place to have this list so another website might need to have it.
When you need a loader what do you do?
If there is no central place to look for this answer, then please share how you find loaders that are needed to solve your webpack file loading problem.
It all depends on your workflow, how u want to load assets at run-time.
For eg, if u have lot of images, it might be a good idea to use a file-loader and place them directly inside the build directory.
The above approach will increase the GET calls and the bundled js file size will not be affeted
If u have less images/small size images then you can use url-loader which converts them into data-URL and put them inside your bundled js files.
The above approach will reduce the GET calls and will slightly increase the bundled js size.
If u want combination of both, then u can set a size limit and fallback loader(file-loader) on url-loader. What this will do is, the size of the dataURL will be calculated.If the size is grater than the limit, the file-loader will be used, which will place it in the build directory.
How I use them
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'images/',
name: '[name][hash].[ext]',
},
},
],
},
{
test: /\.(svg)$/,
exclude: /fonts/, /* dont want svg fonts from fonts folder to be included */
use: [
{
loader: 'svg-url-loader',
options: {
noquotes: true,
},
},
],
},
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
exclude: /images/, /* dont want svg images from image folder to be included */
use: [
{
loader: 'file-loader',
options: {
outputPath: 'fonts/',
name: '[name][hash].[ext]',
},
},
],
}
Is there a way to configure RequireJS to always use a specific plugin, when a certain extension has been found?
I would like to avoid to manually call the plugin like require('es6!myModule')
Some sort of a-la WebPack config is what I'm looking for, but I haven't had much luck in the docs nor the web
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
plugins: ['react-hot-loader/babel'],
},
}
RequireJS is very limited the support it provides for what you are trying to do. It does not have any kind of pattern matching capabilities in the general sense of the word "pattern matching". In particular, there's no way to tell RequireJS to match files with a specific extension. If you must stick with RequireJS, and the set of modules that must get the plugin is a fixed set known when you are building your application, you could generate a map like this:
map: {
"*": {
foo: "plugin!foo",
bar: "plugin!bar",
// ...
}
}
The "*" is not actually a glob or any kind of sophisticated pattern matching. It is more like an encoded keyword that means "any module".
I have an application written in TypeScript that I must be able to run through RequireJS and be able to process through Webpack. I have a few modules that are essentially JSON data. The TypeScript compiler does not like to see plugin names in module imports. So to get everything to work smoothly I keep plugin names out of the TypeScript code code and I use a map like the above to have RequireJS use the json plugin for the modules that need it. I manage the map manually because it is only a few files.
SystemJS supports loading AMD modules and has much more sophisticated configuration facilities than RequireJS. What RequireJS calls a "plugin" is called a "loader" in SystemJS. You can use the meta option to associated a loader with a pattern of files:
{
baseURL: "lib/",
paths: {
// ...
},
meta: {
"something/*.js": {
loader: "some-loader",
}
}
}
I have a TypeScript project which I am bundling with Webpack. It is a demo/docs app for an open source lib I am writing, so I want to show some of the source code as part of the docs.
In my webpack config I have:
loaders: [
{ test: /\.ts$/, loader: 'ts'},
{ test: /\.css$/, loader: 'style!raw' },
{ test: /\.html/, loader: 'html' }
]
which works fine for transpiling and bundling my TypeScript files. In one of my app components I do this:
basicCodeT: string = require('./basic-example-cmp.html');
basicCodeC: string = require('!raw!./basic-example-cmp.ts');
to load the source code into a string which I then want to display in the docs.
As you can see, there is a leading ! in the second line which I discovered seems to "bypass" the default loaders from the config and loads the raw TypeScript as a string.
In my dev build this works, but when I do a "production" build with the UglifyJsPlugin and OccurrenceOrderPlugin, I get the following output:
ERROR in ./demo/src/basic-example-cmp.html
Module build failed:
# ./demo/src/demo-app.ts 24:26-61
which corresponds to the line in the source where I try to require the raw TypeScript.
So, I want to pass basic-example-cmp.ts through the TS compiler as part of the app build, but also want to require it as raw text in the app.
My question then is: Is there a proper way to tell webpack to "ignore" loaders in specific require cases?
Is my way of prepending a ! correct? Is it a hack?
Update
Turns out my problem is simply due to the way Webpack handles HTML templates - it does not like the Angular 2 template syntax, see: https://github.com/webpack/webpack/issues/992
You can add two exclamation to ignore loaders in the webpack config file
!!raw!file.ts
one exclamation will only disable preloaders!
https://webpack.js.org/concepts/loaders/#inline
As far as I know that is the only way you are going to be able to load a file in two different ways. I expect the issue is that your paths are different in your production build.
I would suggest running webpack with the --display-error-details flag to get more info on why it fails.
Is there a proper way to tell webpack to "ignore" loaders in specific require cases?
Yes. Update your test in { test: /\.ts$/, loader: 'ts'}, as desired.
I am using webpack and I need to include some libraries built for requirejs.
Everything worked fine until one of the library declared a css dependency:
define(["css!./stylesheet.css"], function(){ \* module *\ });
Webpack has a css loader too, however it does not load them automatically as requirejs's one does. One must pipe the css loader to the style loader to do so:
require("style!css!./stylesheet.css");
Is there any way to make the prior working? For example, can I overwrite the css loader for this particular library so that it is piped with the style loader ?
I found a nice solution using postLoaders.
Adding
postLoaders: [
{ test: /\.css$/, loader: 'style', include: path.join(__dirname, "pathTo/theLib") }
]
into the module property of the webpack config did the trick.
I have a React application with Components written in ES6 - transpiled via Babel and Webpack.
In some places I would like to include specific CSS files with specific Components, as suggested in react webpack cookbook
However, if in any Component file I require a static CSS asset, eg:
import '../assets/css/style.css';
Then the compilation fails with an error:
SyntaxError: <PROJECT>/assets/css/style.css: Unexpected character '#' (3:0)
at Parser.pp.raise (<PROJECT>\node_modules\babel-core\lib\acorn\src\location.js:73:13)
at Parser.pp.getTokenFromCode (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:423:8)
at Parser.pp.readToken (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:106:15)
at Parser.<anonymous> (<PROJECT>\node_modules\babel-core\node_modules\acorn-jsx\inject.js:650:22)
at Parser.readToken (<PROJECT>\node_modules\babel-core\lib\acorn\plugins\flow.js:694:22)
at Parser.pp.nextToken (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:98:71)
at Object.parse (<PROJECT>\node_modules\babel-core\lib\acorn\src\index.js:105:5)
at exports.default (<PROJECT>\node_modules\babel-core\lib\babel\helpers\parse.js:47:19)
at File.parse (<PROJECT>\node_modules\babel-core\lib\babel\transformation\file\index.js:529:46)
at File.addCode (<PROJECT>\node_modules\babel-core\lib\babel\transformation\file\index.js:611:24)
It seems that if I try and require a CSS file in a Component file, then the Babel loader will interpret that as another source and try to transpile the CSS into Javascript.
Is this expected? Is there a way to achieve this - allowing transpiled files to explicitly reference static assets that are not to be transpiled?
I have specified loaders for both .js/jsx and CSS assets as follows:
module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel'}
]
}
View the full webpack config file
FULL DETAILS BELOW:
webpack.common.js - A base webpack config I use, so I can share properties between dev and production.
Gruntfile.js - Gruntfile used for development. As you can see it requires the webpack config above and adds some development properties to it. Could this be causing the problem?
Html.jsx - My HTML jsx component that tries to import/require the CSS. This is an isomorphic app (using Fluxbile), hence needing to have the actual HTML as a rendered component. Using the require statement seen in this file, in any part of my application, gives the error described.
It seems to be something to do with grunt. If I just compile with webpack --config webpack.common.js then I get no errors.
Short answer: It's a node runtime error. Trying to load CSS on the server in isomorphic apps is not a good idea.
You can't require css in the component that you are rendering on the server. One way to deal with it is to check if it's a browser before requiring css.
if (process.env.BROWSER) {
require("./style.css");
}
In order to make it possible you should set process.env.BROWSER to false (or delete it) on the server
server.js
delete process.env.BROWSER;
...
// other server stuff
and set it to true for the browser. You do it with webpack's DefinePlugin in the config -
webpack.config.js
plugins: [
...
new webpack.DefinePlugin({
"process.env": {
BROWSER: JSON.stringify(true)
}
})
]
You can see this in action in gpbl's Isomorphic500 app.
If you're building an isomorphic app with ES6 and want to include CSS when rendering on the server (important so basic styles can be sent down to the client in the first HTTP response) check out the #withStyles ES7 decorator used in React Starter Kit.
This little beauty helps ensure users see your content with styles when the page is first rendered. Here's an example isomorphic app I'm building leveraging this technique. Just search the codebase for #withStyles to see how it's used. It goes a little something like this:
import React, { Component, PropTypes } from 'react';
import styles from './ScheduleList.css';
import withStyles from '../../decorators/withStyles';
#withStyles(styles)
class ScheduleList extends Component {
We had a similar problem with our isomorphic app (and a lot of other problems, you can find details here). As for the problem with CSS import, at first, we were using process.env.BROWSER. Later we've switched to babel-plugin-transform-require-ignore. It works perfectly with babel6.
All you need is to have the following section in your .babelrc
"env": {
"node": {
"plugins": [
[
"babel-plugin-transform-require-ignore", { "extensions": [".less", ".css"] }
]
]
}
}
After that run your app with BABEL_ENV='node'. Like that:
BABEL_ENV='node' node app.js.
Here is an example of how a production config can look like.
You can also try this
https://github.com/halt-hammerzeit/webpack-isomorphic-tools
or this
https://github.com/halt-hammerzeit/webpack-react-redux-isomorphic-render-example
I used this babel plugin with success to solve a similar issue with less, svg and images. But it should work with any non js assets.
It rewrites all assets imports into variables, so as long as you run the compiled code just on the server and have a bundle built with webpack for the client, it should be fine.
The only drawback is that it onlyworks with named imports, so you'll have to:
import styles from './styles.css';
in order to make it work.
Make sure you are using the loaders in your webpack config:
module: {
loaders: [
{ test: /\.jsx$/, exclude: /node_modules/, loader: "babel" },
{ test: /\.css$/, loader: "style!css" }
]
}
You probably have an error in your Webpack config where you're using the babel-loader for all files, and not just .js files. You want to use a css loader for .css files.
But you shouldn't use import for loading any other module than Javascript modules, because once imports are implemented in browsers, you will only be able to import Javascript files. Use require instead in cases where you need Webpack specific functionality.
ORIGINAL POST
Webpack uses require and Babel lets you use import from ES6 which mostly do the same thing (and Babel transpiles the import to a require statement), but they are not interchangable. Webpacks require function lets you specify more than just a module name, it lets you specify loaders as well, which you cannot do with ES6 imports. So if you want to load a CSS file, you should use require instead of import.
The reason is that Babel is just a transpiler for what's coming in ES6, and ES6 will not allow you to import CSS files. So Babel won't allow you to do that either.
I've finally realised that this error is not originating at the compile stage, but rather at runtime. Because this is an ismorphic app, the components and any dependencies they have will first be parsed on the server (ie, in node). It is this that is causing the error.
Thanks for all the suggestions, I will post more if/when I figure out how to have per-component stylesheets in an isomorphic application.
I also met the same problem when I want to do the server-side render.
So I write a postcss plugin, postcss-hash-classname.
You don't require css directly.
You require your css classname js file.
Because all you require is js file, you can do the server-side render as usual.
Besides, this plugin also use your classname and file path to generate unique hash to solve css scope problem.
You can try it!
Solved With This...
https://github.com/michalkvasnicak/babel-plugin-css-modules-transform
$ npm install --save-dev babel-plugin-css-modules-transform
Include plugin in .babelrc
{
"plugins": ["css-modules-transform"]
}
And Import Css..... Like This Anywhere You Want
const styles = require('./test.css');
OR
import css from './styles.css'
Also See This... Apart From Css Files........................................................ .
https://www.npmjs.com/package/babel-plugin-transform-assets