I use
python manage.py runserver for django and webpack-dev-server --mode=development for template on local development.
My file structure is like this
/ - /myproj/
/defapp/
/frontend/dist/
/frontend/static/
/frontend/templates/
/frontend/node_modules/
/static/
Now I was ready for deployment on server, so I did webpack --mode=production,
It created the /frontend/dist directory....
then,,,How can I use this ?
Just accessing localhost (manage.py runserver) but no templates appears.
GET https://localhost:8008/static/js/dashboard.0c3e9ffe26656a1dd3c7.bundle.js net::ERR_ABORTED 404 (Not Found)
Maybe I don't understand the basic idea of webpack...
It uses dev server for development but in production, it doesn't require server? am I correct?
My webpack.config.js is below.
const path = require('path');
const { merge } = require('webpack-merge');
const BundleTracker = require('webpack-bundle-tracker');
const entries = {}
for (const fileName of require('fs').readdirSync(path.resolve(__dirname, 'static', 'entries'))) {
entries[fileName.split('.')[0]] = `./static/entries/${fileName}`
}
const baseConfig = {
entry: entries,
output: {
filename: 'js/[name].[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
chunks: 'initial',
name: 'vendor',
},
},
},
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new BundleTracker({
path: __dirname,
filename: 'webpack-stats.json',
}),
]
};
const devConfig = merge(baseConfig, {
mode: 'development',
output: {
publicPath: 'http://localhost:3000/static/',
},
devServer: {
client:{
webSocketURL: 'ws://localhost:3000/ws',
},
port: 3000,
hot: true,
host: '0.0.0.0',
allowedHosts: 'all',
//watchOptions: {
// ignored: /node_modules/
//},
headers: {
"Access-Control-Allow-Origin": "*"
}
},
});
const productConfig = merge(baseConfig, {
mode: 'production',
output: {
publicPath: '/static/'
}
})
module.exports = (env, options) => {
return options.mode === 'production' ? productConfig : devConfig
}
Solution
Add this in django setting.
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'frontend/dist'),
)
then it gathers the file to /static/ folder when python manage.py collectstatic
Related
For some reason, webpack is trying to append client to the href of the script tags for my CSS and bundle. The problem with this is that it's wrong. And I don't know how to tell it to trim that part off.
Before moving to webpack, here is how it looks in production when I was building it with Gulp:
notice above how everything was rooted from within the client folder. You don't even see the client folder because I think expressJS said to start from that point so you only see the root of what's in client such as lib, scripts, etc.
here's what the dist directory looked like when I was using Gulp for that:
Here's how I'm serving my static assets. My ExpressJS server sets the root folder for static asses as dist/client. This has always been the case even when I was using Gulp:
.use(
express.static('dist/client', {
maxage: oneYear,
})
)
Forward to now: It's using my new webpack.config now
Here is a Screenshot of dist from IDE as it is now after using webpack:
But now the index.html is gened by webpack:
<!doctype html><html lang="en"><head><title>My Title</title><meta charset="utf-8"><link href="https://ink.global.ssl.fastly.net/3.1.10/css/ink.min.css"><script src="https://ink.global.ssl.fastly.net/3.1.10/js/ink-all.min.js"></script><script src="https://ink.global.ssl.fastly.net/3.1.10/js/autoload.js"></script><link href="../client/lib/assets/css/main.c09764908684c2f56919.css?c09764908684c2f56919" rel="stylesheet"></head><body><div id="app"></div><script src="../client/scripts/app.c09764908684c2f56919.bundle.js?c09764908684c2f56919"></script></body></html>
webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const isProduction = process.env.NODE_ENV === 'production';
const html = () => {
return new HtmlWebPackPlugin({
template: './src/client/index.html',
filename: './client/index.html',
hash: true,
});
};
const copyAllOtherDistFiles = () => {
return new CopyPlugin({
patterns: [
{ from: 'src/client/assets', to: 'client/lib/assets' },
{ from: 'src/server.js', to: './' },
{ from: 'src/api.js', to: './' },
{ from: 'package.json', to: './' },
{ from: 'ext', to: 'client/lib' },
{ from: 'feed.xml', to: 'client' },
{
from: 'src/shared',
to: './shared',
globOptions: {
ignore: ['**/*supressed.json'],
},
},
],
});
};
module.exports = {
entry: './src/client/index.js',
output: {
filename: 'client/scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
target: 'web',
devServer: {
writeToDisk: true,
},
devtool: 'source-map',
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
},
},
},
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
},
],
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['url-loader'],
},
],
},
plugins: isProduction
? [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: isProduction
? 'client/lib/assets/css/main.[hash].css'
: 'main.css',
}),
html(),
copyAllOtherDistFiles(),
]
: [new CleanWebpackPlugin(), html(), copyAllOtherDistFiles()],
};
Notice for my bundle the src generated includes ../client/ and same for my href for the CSS script.
The problem with this is that my app is served from the root of the client folder in dist. You'd think that ../client/ or ./client/ or client/ would work but it doesn't. When I run the site I get this because it can't find the bundle:
As you can see below, everything it stemming from context of the client folder already in the browser:
(what's also odd about this after moving to webpack, is why do I see a client folder if I told ExpressJS to start from the client folder already? When I was using the same exact code with Gulp, I did not see a client folder because I was already in it from the context of the browser)
So when I change the generated index.html manually in my dist folder, just to see if I can fix it, it all resolves just fine (notice I changed it to just lib/ and scripts/):
</script><link href="lib/assets/css/main.c09764908684c2f56919.css?c09764908684c2f56919" rel="stylesheet"></head><body><div id="app"></div><script src="scripts/app.c09764908684c2f56919.bundle.js?c09764908684c2f56919"></script></body></html>
The problem is I don't know how to get webpack to strip out that ..client/ part of the url when it gens the index.html. I've tried adding a publicPath property with '/', or './' or '' but no luck so far.
In other words this does not load: http://localhost:8080/client/scripts/app.b4b3659d9f8b3681c26d.bundle.js
but this does:
http://localhost:8080/scripts/app.b4b3659d9f8b3681c26d.bundle.js
http://localhost:8080/lib/assets/css/main.b4b3659d9f8b3681c26d.css
I think as long as you just write your output assets to same folder with the public folder set at your server, then it would work. Assuming the client will still be the public:
.use(
express.static('dist/client', {
maxage: oneYear,
})
)
I suggest to set entire output as client dir along side with its publicPath in webpack config for client:
output: {
filename: 'scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist/client'),
publicPath: '/'
}
with the setting above, we don't have to specify the folder the html template location:
new HtmlWebPackPlugin({
template: path.resolve(__dirname, 'src/client', 'index.html'),
filename: 'index.html',
hash: true,
});
I don't quite understand yet why this fixed it but here is what made it work.
Definitely didn't need the publicPath:
output: {
filename: 'scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
Changed my static path to be:
.use(
express.static('dist', {
maxage: oneYear,
})
)
move index.html out of the client folder and into the root of dist:
return new HtmlWebPackPlugin({
template: path.resolve(__dirname, 'src/client', 'index.html'),
filename: 'index.html',
hash: true,
});
Same with my bundle
output: {
filename: 'scripts/app.[hash].bundle.js',
publicPath: '/',
path: path.resolve(__dirname, 'dist'),
},
Same with assets:
patterns: [
{ from: 'src/client/assets', to: 'lib/assets' },
I don't see what moving it to the root of dist makes any difference but for some reason rendering / requesting to process index.html from the root of dist instead of dist/client works`
This is the error:
'node"' is not recognized as an internal or external command,
operable program or batch file.
[Finished in 0.139s]
Also, this is coming from atom text editor, if that's necessary information.
Here's my code:
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const isProduction = process.env.npm_lifecycle_event === 'build'
module.exports = {
entry: './src',
// resolve: {
// alias: {
// 'src': path.join(__dirname, '/src'),
// 'libs': path.join(__dirname, '/src/libs'),
// }
// },
devtool: !isProduction && 'source-map',
output: {
path: path.join(__dirname, '/dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
// minify: isProduction && {
// collapseWhitespace: true
// },
minify: isProduction,
inlineSource: isProduction && '\.(js|css)$'
}),
new HtmlWebpackInlineSourcePlugin(),
new OptimizeCssAssetsPlugin({}),
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new CopyWebpackPlugin([
{ from: './src/assets/**/*', to: path.join(__dirname, '/dist'), flatten: false, force: true },
]),
],
devServer: {
stats: 'minimal',
overlay: true,
contentBase: path.resolve('src/assets'),
// contentBase: path.join(__dirname, '/src/assets'),
}
}
Am I just missing a package for this, or is there an error in my quote, or what?
Mmmmm... how are you running the code?
Most probable answer, based on your provided info --> you have any node installation in your system and/or your node installation is not accesible or included into your path.
Check https://nodejs.org/en/download/
Taken from webpack docs:
Since webpack v5.0.0-beta.1 the minimum Node.js version to run webpack
is 10.13.0 (LTS)
You need to install node.js
What I'm trying to achieve is to create a separate webpack assets file for copying static assets from the src folder to the web folder.
node version: 8.15.0
yarn version: 1.13.0
webpack: 4.19.1
copy-webpack-plugin: 6.0.0
To start, I already have a webpack.common.js file which deals with all the js files, and I have created the assets file, which can be seen below.
When I run
webpack --config=webpack/webpack.assets.js --mode development --progress --color
or
webpack --config=webpack/webpack.config.js --config=webpack/webpack.assets.js --mode development --progress --color --env development
I get this error ERROR in Path must be a string. Received undefined and I can't figure it out where it comes from.
By the way I just started dealing with webpack recently.
webpack.common.js
const webpack = require('webpack');
const path = require('path');
const PATHS = {
src: path.join(process.cwd(), 'src', 'js'),
dist: path.join(process.cwd(), 'web', 'js')
};
module.exports = {
entry: {
homepage: path.resolve(PATHS.src, 'pages/homepage.js'),
otherfile: path.resolve(PATHS.src, 'pages/othefile.js'),
}
output: {
path: PATHS.dist,
filename: '[name].js',
chunkFilename: '[name].js',
publicPath: '/js/'
},
...
}
webpack.assets.js
const webpack = require('webpack');
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const PATHS = {
src: path.join(process.cwd(), 'src', 'svg'),
dist: path.join(process.cwd(), 'web', 'svg')
};
module.exports = (env) => {
const svgFormat = env === 'production' ? '[name].[hash].[ext]' : '[name].[ext]';
return merge(commmonConfig, {
entry: [
path.resolve(PATHS.src, 'logo1.svg'),
path.resolve(PATHS.src, 'logo2.svg')
],
output: {
path: PATHS.dist
},
module: {
rules: [
{
test: /\.(svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: svgFormat,
},
},
],
},
]
},
plugins: [
new CopyPlugin([
{
from: PATHS.src,
to: PATHS.dist,
force: true,
toType: 'dir'
},
{
copyUnmodified: true,
debug: 'debug'
}
])
]
});
};
What I would like is to be able to run the assets commands with no errors, as the actual files get copied correctly.
Any ideas are very much appreciated!
You have passed your options object as a second pattern.
Move it outside of the patterns array and pass it as the second parameter instead:
plugins: [
new CopyPlugin(
[
{
from: PATHS.src,
to: PATHS.dist,
force: true,
toType: 'dir'
}
],
{
copyUnmodified: true,
debug: 'debug'
}
)
]
You get the error as your options object is being treated as a pattern but does not have a from property.
i am getting this issue webpack.validateSchema is not a function when i setting up webpack and react below i shared my webpack.config.js
const path = require('path');
const merge = require('webpack-merge');
const webpack = require('webpack');
const TARGET = process.env.npm_lifecycle_event;
const PATHS = {
app: path.join(__dirname, 'app'),
build: path.join(__dirname, 'build')
};
const common = {
entry: {
app: PATHS.app
},
output: {
path: PATHS.build,
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.css$/,
loaders: ['style','css'],
include: PATHS.app,
}
]
}
};
if(TARGET === 'start' || !TARGET){
module.exports = merge(common, {
devtool: 'eval-source-map',
devServer: {
contentBase: PATHS.build,
historyApiFallback: true,
hot: true,
inline: true,
progress: true,
stats: 'errors-only',
host: process.env.HOST,
port: process.env.PORT || 3000
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
});
}
if(TARGET === 'build'){
module.exports = merge(common, {});
}
There are a couple of errors to fix:
Instead of extension: ['','.js','.jsx'], use extensions: ['.js','.jsx']. There's no need for the empty entry since webpack 2 and it will complain about it.
Instead of ['style','css'], use ['style-loader','css-loader']. Since webpack 2, it doesn't provide the shortcut by default.
Instead of babel?cacheDirectory, use babel-loader?cacheDirectory. I might rewrite the definition through use and options as in the webpack book chapter.
I know this is a common question for webpack; it's really hard to debug something if it won't give you any information about the cause or location of the error.
I'm getting the error:
Error: 'output.filename' is required, either in config file or as --output-filename
I know it has to do with a syntax error somewhere, but I'm too new to webpack to figure it out.
Here's my config file. It's called "webpack.config.js" in the root folder (i.e. the folder in which I initially ran: npm init).
const webpack = require('webpack');
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const RewriteImportPlugin = require("less-plugin-rewrite-import");
const root_dir = path.resolve(__dirname)
const src_dir = path.resolve(__dirname, "webpack_src")
const build_dir = path.resolve(__dirname, "webpack_bin")
const node_mod_dir = path.resolve(__dirname, 'node_modules');
const extractLESS = new ExtractTextPlugin('style.css');
const config = {
entry: {
index: path.resolve(src_dir, 'index.js')
},
output: {
path: build_dir,
filename: 'bundle.js'
},
resolve: {
modules: [root_dir, 'node_modules'],
},
module: {
rules: [
{
loader: 'babel-loader',
test: /\.(js)$/
},
{
use: extractLESS.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'less-loader',
options: {
paths: [root_dir, node_mod_dir],
plugins: [
new RewriteImportPlugin({
paths: {
'../../theme.config': __dirname + '/semantic_ui/theme.config',
}
})
]
}
}]
}),
test: /\.less$/
},
{
use: ['file-loader'],
test: /\.(png|jpg|gif|woff|svg|eot|ttf|woff2)$/
},
]
},
plugins: [
extractLESS,
new webpack.optimize.ModuleConcatenationPlugin()
]
};
module.exports = {
config
};
You're exporting module.exports = { config }, which means that you are exporting an object with one property, namely config, but webpack expects the object to be your entire config. Webpack requires output.filename, whereas you only provide config.output.filename.
The export should be your config:
module.exports = config;