I'm trying to implement SSR using React (create-react-app) and Firebase. To do so, I'm currently working on my webpack configuration:
module.exports = [{
entry: './src/index.js',
module: {
rules: [
{test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/},
{test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/},
{test: /\.css$/i, use: ['style-loader', 'css-loader']},
{test: /\.(png|jpe?g|gif|svg|otf)$/i, loader: 'file-loader', exclude: /node_modules/},
]
},
output: {
filename: 'public/bundle.js',
path: __dirname
}
}];
The webpack works fine without any errors (some size limit warnings, but from what I've read online I can ignore them). Anyways somehow it's adding every single asset to my root folder (not even inside of my directory), which is kind of ugly and confusing. - How can I change the output target of these assets?
Change your output to
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, 'dist/assets')
}
This will put your bundle.js in the dist/assets/js directory inside your project's root.
As another example, if you want your bundle.js in public/js folder in your project's root, configure it like this
output: {
filename: 'js/bundle.js',
path: path.resolve(__dirname, 'public')
}
If you leave out the path option entirely, it'll default to the dist directory.
Or refer this Webpack documentation page and adjust the values accordingly.
Also, don't forget to import the path module
const path = require('path');
Related
In our project, I'm trying to refactor all our components to have a .jsxfile extension rather than .js. My webpack.config.babel file now looks like this:
import fs from "fs"
const babelrc = JSON.parse(fs.readFileSync("./.babelrc"))
export default {
module: {
loaders: [
{
test: /\.js$/,
loader: "babel-loader",
query: babelrc,
exclude: /(node_modules|bower_components)/,
},
{
test: /\.jsx$/,
loader: "babel-loader",
query: babelrc,
exclude: /(node_modules|bower_components)/,
},
{
test: /\.json$/,
loader: "json-loader",
},
{
test: /\.css$/,
loader: 'style-loader!css-loader',
},
],
},
}
However when I try to run import Main from './components/Main/Main';
in my client.js file, it shows me
Module build failed: Error: ENOENT: no such file or directory, open '/foo/src/components/Main/Main.js'
# multi babel-polyfill webpack-dev-server/client?/ webpack/hot/dev-server ./src/client.js
I'm new to babel and webpack. What other places to I need to register the jsx file extension?
Take a look at the documentation for resolve.extensions:
https://webpack.js.org/configuration/resolve/#resolveextensions
You can add the following to your Webpack config to also automatically resolve files with the .jsx extension by adding the following to your config:
resolve: {
extensions: ['.js', '.jsx']
}
Btw, you can also optimize your loader config by removing the separate .jsx loader and make the first loader test for /\.jsx?$/
This is my webpack.config file. When I run webpack, bundle.js correctly writes to project/dist/assets/bundle.js.
However, when I run npm start to serve up the files, I get an error:
Error: output.path needs to be an absolute path or /.
So... if I make the path absolute: "/dist/assets" or path: __dirname + "/dist/assets" then it serves up the files fine, and emits bundle.js, but it doesn't actually write it to my project/dist/assets folder.
The page looks fine and when I view source, I see <script src="/assets/bundle.js"></script> but it only exists on the localhost (publicPath).
Where am I going wrong? The goal being for npm start to write the bundle to my project folder AND serve it up with devServer.
var webpack = require("webpack");
module.exports = {
entry: "./src/index.js",
output: {
path: "./dist/assets",
filename: "bundle.js",
publicPath: "/assets"
},
devServer: {
inline: true,
contentBase: "./dist",
port: 3000
},
module: {
loaders: [{
test: /\.js$/,
exclude: /(node_modules)/,
loader: ["babel-loader", "babel-loader?presets[]=latest,presets[]=stage-0,presets[]=react"]
}, {
test: /\.json$/,
exclude: /(node_modules)/,
loader: "json-loader"
}, {
test: /\.css$/,
loader: "style-loader!css-loader!autoprefixer-loader"
}, {
test: /\.scss$/,
loader: "style-loader!css-loader!autoprefixer-loader!sass-loader"
}]
}
}
Use path for this:
var path = require('path');
....
output: {
path: path.join(__dirname, './dist/assets'),
Being new to webpack, the answer might be staring me down but I don't see it. No matter how I try to pass them along, the file-loader options aren't found.
I'm using file-loader and I'm trying to pass a publicPath (or simply anything, at first) along as an option. I went into the file loader source code and added a log for all the options it detected, but they always come up empty.
webpack.config.prod.js
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: [
'./src/index.js'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'idlink-1.1.1.js',
publicPath: ''
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'})
],
module: {
loaders: [
{
exclude: /node_modules/,
loader: 'babel',
query: { presets: ['react', 'es2015', 'stage-1'] }
},
{test: /\.css$/, loader: "style-loader!css-loader" },
{test: /\.scss$/, loaders: ["style", "css", "sass"]},
{test: /\.less$/, loader: "style-loader!css-loader!less-loader" },
{
test: /\.(jpe?g|png|gif|svg|pdf)$/i,
loader: "file",
options: { publicPath: 'https://apps.ixordocs.be/'}
},
{test: /\.gif$/, loader: "url-loader?mimetype=image/png" }
]
},
}
I've also tried with
loader: "file-loader"
as well as added the options as one string like this
loader: "file?name=[name].[ext]&publicPath=https://apps.ixordocs.be/"
Some context info:
I don't want to have a hardcoded publicPath defined in my output: {}, i want to grab it dynamically from a parameter placed on the div that my plugin is loaded into.
I've tried using the __webpack_public_path__ variable and it works, but not for images. The public path is grabbed from the parameter, set, and used to fetch a chunk. Somehow it has no effect on images though. If I hardcode a publicPath under output, it DOES work for images. This leads me to believe there is a problem with the loader's communication to the variable, so the idea is to get the options working and eventually try to pass a dynamic publicPath in there.
Your question is totally valid based on the documentation of the loader on both loader's GitHub repo and webpack docs. The problem is the publicPath and outputPath features are implemented in a pull request that is merged but not yet released to a new version of loader, and the README on npm doesn't mention the features for the same reason.
You can still use these features by installing from the GitHub repo with npm install webpack/file-loader --save-dev and your options should work. If not try replacing options with query.
{
test: /\.(jpe?g|png|gif|svg|pdf)$/i,
loader: "file-loader",
query: { publicPath: 'https://apps.ixordocs.be/'}
}
Using URLs for publicPath is also valid because it happens often that you want to load your assets from a CDN or another server.
I am pulling my hair off...
Feels like I have tried everything.
This is my webpack config:
var publicConfig = {
context: path.join(__dirname, 'src'),
entry: [
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000',
'./public.jsx',
],
output: {
path: path.join(__dirname, 'app'),
filename: 'publicBundle.js',
publicPath: '/assets/',
},
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader'},
//{ test: /\.css$/, loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]' },
// { test: /\.css$/, loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]' },
{ test: /\.css$/, loader: "style!css" },
{
test: /\.(jpg|png)$/,
loader: 'url?limit=25000'
},
{ test : /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader : 'file-loader' }
]
},
resolve: {
extensions: ['', '.js', '.jsx', '.json']
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
};
When defining images in my css files the images gets added to the /assets/ folder, which is exactly what I want... However, I want to be able to call image paths from inline ( the html views aswell ). But the images doesnt get copied to /assets/ unless I target them from my css file.
I tried importing them by:
import logo from './images/animus_logo_blacktext.png'
But it still doesnt appear in my assets.
What is the best practice for image paths inline?
Is it possible the images are very small? The limit you configured in URL-loader means that all images under 25000 bytes will be inlined (as data URI's) instead of served as a file. Files larger than 25000 bytes will be treated by url-loader the same way file-loader treats them.
I think you want to try https://www.npmjs.com/package/copy-webpack-plugin. This is a webpack plugin that copies individual files or entire directories to the build directory.
Switch to the file-loader instead of the url loader. The images may be under your limit of 25000 (25kb).
Without modifying your webpack configuration you could try this:
import logo from 'file-loader!./images/animus_logo_blacktext.png'
You should see the image in your assets.
I am using webpack with babel-loader to transform .jsx react files.
However, adding a file-loader or style- and css-loader does not correctly process the images required() in the react components or style sheets.
They get recognized by webpack and copied to the dist folder. The path to the image file is correct, I've verified this in the css and js output.
The server is also able to display the files, I've checked with some manually copied ones.
What is happening is that the images themselves get corrupted. No image viewer nor the browser can display the image which results in an invisible image in the browser.
What I've tried so far:
using only babel-loader as suggested in: https://github.com/webpack/file-loader/issues/35, results in Error: No handler for file type.
using file-loader directly
using image-webpack-loader (which seems to be using file-loader under the hood)
using IsomorphicLoaderPlugin (https://github.com/jchip/isomorphic-loader) which seems to be a simpler alternative to webpack-isomorphic-tools
using css background-images with url() and ExtractTextPlugin('style-loader", 'css-loader')
All of the above steps resulted in either errors with webpack not finding an appropriate handler or corrupted image files.
Here is my current webpack config for reference (I've included all of it in case there are any problems/conflicts I am overlooking):
var ExtractTextPlugin = require('extract-text-webpack-plugin'),
webpack = require('webpack');
IsomorphicLoaderPlugin = require("isomorphic-loader/lib/webpack-plugin");
module.exports = {
context: __dirname + '/client',
entry: ['babel-polyfill', './index.jsx'],
output: {
filename: 'app.js',
path: __dirname + '/dist',
publicPath: '/'
},
resolve: {
ignore: /node_modules/,
extensions: ['', '.js', '.jsx']
},
devtool: 'source-map',
plugins: [
new ExtractTextPlugin('styles.css'),
new IsomorphicLoaderPlugin({ keepExistingConfig: false }),
new webpack.DefinePlugin({
"process.env": {
BROWSER: JSON.stringify(true)
}
})
],
module: {
preLoaders: [
{
loaders: ['isomorphine']
}
],
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
exclude: /node_modules/,
query: {
cacheDirectory: true,
plugins: ['transform-runtime', 'transform-decorators-legacy', 'transform-class-properties', 'transform-object-rest-spread'],
presets: ['react', 'es2015', 'stage-0']
}
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: "file!isomorphic"
}
]
}
};