Django webpack not loading images from static files - reactjs

I'm in the process of making a website using django and react. I'm using client side rendering in react, instead of handling all the urls with django, and I stumbled upon the problem of not being able to refresh pages from urls other than the base url. From what I understood the easiest solution was webpack and it's historyApiFallback. Anyway, now that I've configured webpack, historyApiFallback doesn't work, and my static images will no longer load... Hopefully someone can help me out here, need it big time.
webpack.config.js
const path = require("path");
const BundleTracker = require('webpack-bundle-tracker');
const HtmlWebpackPlugin = require("html-webpack-plugin");
var config = {
context: __dirname,
entry: './src/index.js',
output: {
path: path.join(__dirname, 'assets/dist'),
filename: "main.js",
publicPath: '/'
},
devServer:{
historyApiFallback: true
},
plugins: [
new BundleTracker({ filename: './webpack-stats.json' }),
new HtmlWebpackPlugin({
template: './public/index.html'
})
],
devtool: 'hidden-source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.css$/,
use: [
'style-loader', 'css-loader'
]
},
{
test: /\.(png|jpg|jpeg|gif)$/,
type: 'asset/resource',
use: [
'url-loader'
]
},
]
}
}
module.exports = () => {
return config
};
settings.py
FRONTEND_DIR = os.path.join(BASE_DIR, 'frontend')
STATIC_URL = 'static/dist/'
STATIC_ROOT = os.path.join(FRONTEND_DIR, "assets/dist/")
STATICFILES_DIRS = (
os.path.join(FRONTEND_DIR, "static/dist/"),
)
MEDIA_URL = '/Images/'
MEDIA_ROOT = os.path.join(FRONTEND_DIR, '/src/Images')
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'assets/dist/', # must end with slash
'STATS_FILE': os.path.join(FRONTEND_DIR, 'webpack-stats.json')
}
}
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('', TemplateView.as_view(template_name='index.html')),
re_path(r'^api/news/', views.news_list),
path('api/news/<int:id>/', views.news_detail),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
This is how my files look like: /assets/ is where the webpack bundle ends up and /static/ is the publicPath. It works fine with my js files and css files, they are all fetched correctly from /static/dist. However, my images and being fetched from /assets/dist/ and I'm getting 404 errors on all of them. I also have images that are uploaded via models and those work fine... Let me know if I need to add any more files/info and thanks in advance! Also, if anyone knows why my historyApiFallback isn't working, please tell me...
Second image is the error message when i try to fetch the image.

Related

React - importing images [duplicate]

This question already has answers here:
Load images based on dynamic path in ReactJs
(4 answers)
Closed 5 years ago.
I want to have a global variable or something else so that i can easily change path if i need to. I would also like to have a different path when when i build it.
Is there a better way to import without using require?
const URL="./../../img";
//withURL doesn't work
export const logo1 = require(URL+ "/Global/logo1.png");
//this works but too long
export const logo2 = require("./../../img/Editorial/logo2.jpg");
Any idea? Is there a way in webpack that i can set this up?
Here is my webpack:
var webpack = require("webpack");
var path = require("path");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");
var extractPlugin = new ExtractTextPlugin({
filename: "App.css"
});
module.exports = {
entry: './src/js/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['react', 'es2015']
}
}
]
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: ['css-loader']
})
},
{
test: /\.html$/,
use: ['html-loader']
},
{
test: /\.(png|jpg|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name:'[name].[ext]',
outputPath: 'img/'
}
}
]
}
],
},
plugins: [
extractPlugin,
new HtmlWebpackPlugin({
template: 'src/index.html'
})
]
};
This is something done through webpack with the url-loader plugin.
This plugin allows you to require a resource, like an image, and it returns a url for it.
import imageUrl from './url/image.png';
console.log(imageUrl) // "/public/path/0dcbbaa7013869e351f.png"
The url is the content hash of the resource, so that it can be long-term cached.
However, you also want that the path to the resource is generated on runtime. If you are using ES6 modules, you can't do that (well, you can using this syntax https://webpack.js.org/api/module-methods/#import-), but from your example, it seems you aren't since you use require. In that case, if you have correctly configured the url-loader, it seems your issue is with
const URL="./../../img";
export const logo1 = require(URL+ "/Global/logo1");
the path does not end on .png or some extension that has been defined in your webpack config. Did you try adding .jpg?

issue with webpack-server 2

When i run webpack server, it redirects me to folders of project not my index.html, but if I open it without webpack server it works fine, and nothing in network tab. I think my webpack.config.js not loaded correctely!
my webpack.confing.js :
const ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require("path");
module.exports = {
entry : './src/app.js',
output : {
path : path.resolve(__dirname,'dist'),
filename : 'app.bundle.js'
},
module : {
rules : [
{test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ['css-loader','sass-loader'],
publicPath: "/dist"
})}
]
},
plugins: [
new ExtractTextPlugin({
filename: "app.scss",
disable: false,
allChunks: true
})
]
}
The problem is that you have misunderstood the public path concept that has nothing to do with file system path. That is, the publicPath is only related to the url.
url = `${host}:${port}${publicPath}${bundle}`
Only change your extract text plugin parameter publicPath for '/'

HMR Webpack Configuration, giving a 404

I am trying to achieve some sort of auto reloading in my project using webpack-dev-server and react-hot.
I am using babel to transform my js from a src directory to a public directory.
With my current config I can see that the .json and .js update files are making it to the public directory.
But in my error console I can see this:
app.js:4473 GET http://localhost:3000/sockjs-node/info?t=1473946358314 404 (Not Found)AbstractXHRObject._start # app.js:4473(anonymous function) # app.js:4362
app.js:795 [WDS] Disconnected!
I have a webpack.config.js (baseConfig) which looks like this:
require('dotenv').config();
var path = require('path');
var autoprefixer = require('autoprefixer');
var precss = require('precss');
var cssnano = require('cssnano');
var ROOT_PATH = path.resolve(__dirname, 'src');
var BUILD_PATH = path.resolve(ROOT_PATH, '../public');
module.exports = {
entry: '',
output: {
path: BUILD_PATH,
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.jsx?$/, // test for js and jsx files only
loader: ['babel'],
exclude: /node_modules/,
query: {
"presets": ["es2015", "react"],
"ignore": ["/node_modules/"],
}
},
{
test: /\.css$/,
loaders: [
'isomorphic-style-loader',
'css-loader',
'postcss-loader'
],
exclude: /node_modules/
}
]
},
postcss: function() {
return [autoprefixer({browsers: ['last 2 versions']}), precss, cssnano];
},
plugins: []
}
Also a webpack-client-config.js, which looks like this:
require('dotenv').config();
var webpack = require('webpack');
var path = require('path');
var ROOT_PATH = path.resolve(__dirname, 'src');
var BUILD_PATH = path.resolve(ROOT_PATH, '../public');
var baseConfig = require('./webpack.config.js');
baseConfig.entry = [
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:3000',
(ROOT_PATH + '/client-render.js'),
];
baseConfig.plugins = [
new webpack.HotModuleReplacementPlugin(),
]
baseConfig.devServer = {
hot: true,
publicPath: 'http://localhost:3000'
}
module.exports = baseConfig;
I have obviously mis-understood something about webpack, anyone care to enlighten me as to why this is not working? I can visit localhost:3000/app.js and can see the script right there in the browser. I set public as static with express.

The following modules couldn't be hot updated: (Full reload needed)

I'm trying to setup hot module reloading in a react/typescript (with TSX) environment. I have used the react/redux real-world example as a model in getting things going, and this is what I have so far:
server.js
var webpack = require('webpack')
var webpackDevMiddleware = require('webpack-dev-middleware')
var webpackHotMiddleware = require('webpack-hot-middleware')
var config = require('./webpack.config')
var app = new (require('express'))()
var port = 3000
var compiler = webpack(config)
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }))
app.use(webpackHotMiddleware(compiler))
app.use(function(req, res) {
res.sendFile(__dirname + '/index.html')
})
app.listen(port, function(error) {
if (error) {
console.error(error)
} else {
console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)
}
})
webpack.config.js
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve('./src/index.tsx'),
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({ template: './index.html' })
],
module: {
loaders: [
{ test: /\.tsx?$/, loader: 'ts-loader' }
]
},
resolve: {
extensions: ['', '.ts', '.tsx', '.js', '.json']
},
}
index.tsx
import * as React from 'react';
import { render } from 'react-dom';
import Root from './containers/root';
render(
<Root />,
document.getElementById('root')
);
containers/root.tsx
import * as React from 'react';
export default class Root extends React.Component<void, void> {
render(): JSX.Element {
return (
<p>boom pow</p>
);
}
}
Changing <p>boom pow</p> to <p>boom boom pow</p> in the root element kicks off this in the javascript console in the browser:
[HMR] bundle rebuilding
client.js?3ac5:126 [HMR] bundle rebuilt in 557ms
process-update.js?e13e:27 [HMR] Checking for updates on the server...
process-update.js?e13e:81 [HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
process-update.js?e13e:89 [HMR] - ./src/containers/root.tsx
process-update.js?e13e:89 [HMR] - ./src/index.tsx
I've stepped through these steps as best I can tell, but am still having no luck.
What am I missing?
The problem, as mentioned by commenters, was missing in my loader - I'm not sure if this had anything to do with it, but I also switched to using babel after typescript - and having typescript compile to ES6. New config below:
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve('./src/index.ts'),
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({ template: path.resolve('./src/index.html') })
],
module: {
loaders: [
{ test: /\.tsx?$/,
loaders: [
'react-hot',
'babel?presets[]=es2015',
'ts-loader'
]
},
{ test: /\.json$/,
loader: 'json'
}
]
},
resolve: {
extensions: ['', '.ts', '.tsx', '.js', '.json']
},
}
if someone still struggles with this see the readme: https://github.com/webpack-contrib/webpack-hot-middleware/blob/master/README.md
This module is only concerned with the mechanisms to connect a browser client to a webpack server & receive updates. It will subscribe to changes from the server and execute those changes using webpack's HMR API. Actually making your application capable of using hot reloading to make seamless changes is out of scope, and usually handled by another library.
webpack-hot-middleware doesn't handle hot reload, you'd need to use react-hot-loader for example

variable config file based on environment - reactjs, webpack

I need bunch of global variables in my reactjs components(example: hostnames, token, api urls, etc) based on the environment. but I don't want to add it to the js individually. I would like to create project.config file to set up prod:{hostname:example.com, api-url:prod, etc} and dev:{hostname:localhost.com, api-url:dev, etc}, I installed loose-envify, but I have to specify for each var.
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://example.com:3000',
'webpack/hot/only-dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify('production')}),
new ExtractTextPlugin("static/super.css", {
allChunks: true
})
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
},
{ test: /\.scss$/,
loaders: ["style", "css", "sass"],
include: path.join(__dirname, 'src')
}
]
}
};
Did you try to stringify a config json that can have some common and overridden properties for dev or prod?
Which will be given to the new webpack.DefinePlugin({...})?
I was trying to try something similar and tried following which seems to work fine.
In your webpack config add a DefinePlugin. Following is my webconfig:-
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.environment),
}
})
],
Now while compiling use the following commands:-
environment=local webpack (for local)
environment=development webpack(for dev)
environment=production webpack(for prod)
Now if you see I have set 'NODE_ENV' with the cli input so when 'NODE_ENV' is production as value, the webpack automatically minifies your output bundle.
Now say you have API url declared in a file(I had Constants.jsx), so I added following to constants.jsx. So basically you can read the NODE_ENV set in webpack config in this Constants.jsx and import them in your components from where APIS are called by exporting it from here.
const api_url=function(){
let api_url='';
if(process.env.NODE_ENV == 'local'){
api_url= 'http://localhost:8002/api/v0';
}
else if(process.env.NODE_ENV == 'development'){
api_url = 'https://development/api/v0';
}
else if(process.env.NODE_ENV == 'production'){
api_url = 'https://production/api/v0';
}
return api_url;
}
export const url= api_url();
Hope it helped!

Resources