I have a React app, served via ExpressJS. I have configured Webpack to create .gz assets.
However HtmlWebpackPlugin creates the bundle in my index.html as a .js file.
I assume this is because in the output prop in my webpack.prod.js I have the filename with a .js extention.
How can I configure this to return the .gz extension when supported?
Express App
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.resolve(__dirname, '../dist')));
app.get('*.js', function(req, res, next) {
req.url = req.url + '.gz';
res.set('Content-Encoding', 'gzip');
next();
});
app.get('/healthz', (req, res) => res.send('OK'));
app.get('*', (req, res) =>
res.sendFile(path.resolve(__dirname, '../dist/index.html'))
);
const PORT = process.env.SERVER_PORT || 3000;
const HOST = process.env.SERVER_HOST || '127.0.0.1';
app.listen(PORT);
console.log(`API started on ${HOST}:${PORT}`);
webpack.common.js
const commonPaths = require('../common-paths');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
context: commonPaths.appPath,
entry: './index.jsx',
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [
{ test: /\.(jsx?)$/, exclude: /node_modules/, use: ['babel-loader'] }
]
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'initial',
test: 'vendor',
name: 'vendor',
enforce: true
}
}
}
},
plugins: [
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8
}),
new HtmlWebpackPlugin({
title: 'Web App',
template: commonPaths.projectRoot + '/public/index.html',
inject: 'body'
})
]
};
webpack.prod.js
const commonPaths = require('../common-paths');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
devtool: 'source-map',
mode: 'production',
output: {
filename: 'static/[name].[hash].min.js',
path: commonPaths.outputPath
},
plugins: [
new ExtractTextPlugin({
filename: 'static/styles.[hash].min.css',
allChunks: true
})
]
};
I have also tried the following in my Express App incase it was failing in serving the files...
const express = require('express');
const path = require('path');
const app = express();
app.use(
express.static(path.resolve(__dirname, '../dist'), {
index: false,
fallthrough: true,
setHeaders: (res) => {
res.set('Content-Encoding', 'gzip');
}
})
);
app.get('/healthz', (req, res) => res.send('OK'));
app.get('*', (req, res) =>
res.sendFile(path.resolve(__dirname, '../dist/index.html'))
);
const PORT = process.env.SERVER_PORT || 3000;
const HOST = process.env.SERVER_HOST || '127.0.0.1';
app.listen(PORT);
console.log(`API started on ${HOST}:${PORT}`);
Related
I am struggling a bit to find a solution to using webpack on the both the frontend and the server part of a nodejs project.
I am building an express solution with different API endpoints and a frontend that uses EJS for templating that will use these endpoints for data handling.
Basically what I am trying to achieve is to using webpack to compile my SCSS and JS on the frontend and also a solution that will compile EJS and inject the CSS and JS bundles into the frontend.
My current server.js
const express = require('express')
const formidable = require('express-formidable');
const session = require('express-session')
const bodyparser = require('body-parser')
const app = express()
const path = require('path');
const auth = require('./app/middleware/authorization/auth')
const upload = require('./app/middleware/filehandling/upload')
app.set('port', process.env.PORT || 8080);
app.set('view engine', 'ejs')
app.set('views', path.join('views'));
app.use(session({
secret: hash.getRandomString(16),
resave: true,
saveUninitialized: true
}))
app.use(express.json())
app.use('/public', express.static(path.resolve(__dirname, 'public')));
app.use(formidable());
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyparser.urlencoded({ extended: true }))
app.use(bodyparser.json())
//DIFFERENT ROUTES DOWN HERE
app.listen(3000, () => {
console.log('listening on port 3000')
})
My folder structure is
public
- upload/
src
- scss/
- index.js
views
- partials/
- index.ejs
- login.ejs
I have a current webpack.config.dev.js that I am using for static HTML/CSS/JS project that are building and compiling SCSS and JS into bundles.
const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
// const ExtractText = require('extract-text-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devMode = process.env.NODE_ENV !== 'production'
const dirNodeModules = 'node_modules';
const dirAPP = path.join(__dirname, 'src/app');
const dirAssets = path.join(__dirname, 'src/assets');
const packageJson = require('./package.json')
var config = {
entry: {
bundle: path.join(dirAPP, 'index')
},
resolve: {
modules: [
dirNodeModules,
dirAPP,
dirAssets
]
},
plugins: [
new webpack.DefinePlugin({
devMode: devMode
}),
new HTMLWebpackPlugin({
template: path.join('src', 'index.html'),
inject: true
}),
new MiniCssExtractPlugin({
filename: packageJson.name + '.[chunkhash].min.css'
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader', 'eslint-loader']
},
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
config: {
path: 'postcss.config.js'
}
},
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: 'file?=name/fonts/[name].[ext]'
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [{
loader: 'file-loader',
options: {
name: '[name]-[hash:8].[ext]',
pluginPath: dirAssets + '/images/',
outputPath: dirAssets + '/images/'
}
}]
}]
}
}
module.exports = config;
And a webpack.config.build.js
const path = require('path');
const merge = require('webpack-merge');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpackConfig = require('./webpack.config');
const packageJson = require('./package.json');
module.exports = merge(webpackConfig, {
devtool: 'source-map',
output: {
path: path.join(__dirname, 'dist'),
filename: packageJson.name + '.[chunkhash].js'
},
plugins: [
new CleanWebpackPlugin(['dist'])
]
});
Which I call using
"dev": "cross-env NODE_ENV=dev webpack-dev-server --progress --mode development --config webpack.config.dev.js",
"build": "webpack -p --progress --mode production --config webpack.config.build.js"
I am a bit unsure how I can achieve this.
Hi I am trying to establish my project in react.
My Current project structure is
-public
--w
---dist
----bundle.js
---index.html
-server
--server.js
-src
--app.js
-webpack.config.js
-package.json
-.babelrc
I am using node js as server
I want my static files to called on localhost:port//w/
and api call on localhost:port//api/
I have tried manipulating server.js, routes, project structure and webpack.config but could not get success.
server.js
const express = require('express');
const path = require('path');
const app = express();
const port = 3000;
const publicPath = path.join(__dirname, '../public/w');
app.use(express.static(publicPath));
app.get('/w/*', (req, res) => {
console.log('Calling..');
res.sendFile(path.join(publicPath, 'index.html'));
})
app.get('/api/test', (req, res) => {
res.send("Hello");
})
app.listen(port, () => {
console.log(`Server is up on ${port}`);
})
webpack.config
const path = require('path');
module.exports = {
entry: './src/app.js',
output: {
path: path.join(__dirname, 'public', 'w', 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
},
devtool: 'inline-source-map',
devServer: {
contentBase: path.join(__dirname, 'public', 'w'),
publicPath: '/dist/',
historyApiFallback: true
}
}
My routes
const AppRouter = (props) => {
return (
<BrowserRouter>
<div>
<Switch>
<Route path="/" component={Dashboard} />
<Route path="/w/resume-builder" component={ResumeBuilder} />
</Switch>
</div>
</BrowserRouter>
)
}
Can anyone suggest what should I do or What I am missing in it?
You have to do some restructure
-public
--dist
---bundle.js
--index.html
-server
--server.js
-src
--app.js
-webpack.config.js
-package.json
-.babelrc
Server.js
const express = require('express');
const path = require('path');
const app = express();
const port = 3000;
const publicPath = path.join(__dirname, '../public');
app.use(express.static(publicPath));
//keep all api before fallback
app.get('/api/test', (req, res) => {
res.send("Hello");
});
app.get('/w/*', (req, res) => {
console.log('Calling..');
res.sendFile(path.join(publicPath, 'index.html'));
});
app.listen(port, () => {
console.log(`Server is up on ${port}`);
});
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/app.js',
output: {
path: path.join(__dirname, 'public', 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
},
devtool: 'inline-source-map',
devServer: {
contentBase: path.join(__dirname, 'public'),
publicPath: '/dist/',
historyApiFallback: true
}
}
You can keep your routes same.
I have a webpack plugin as below, I want to user localhost secure , how can I do that ? I do not see any require('http') as in the nodejs server, how can I do that with this webpack configuration ?
Should I prepare some SSL certificate ? If so where should I use them ?
Here is webpack configuration for development
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false, // since we use CopyWebpackPlugin.
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
// publish the new Port, necessary for e2e tests
process.env.PORT = port
// add port to devServer config
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})
})
devServer: {
https: true,
...
},
Hello I'm new to react and I'm trying to attach express framework with react, I followed this tutorial: https://blog.hellojs.org/setting-up-your-react-es6-development-environment-with-webpack-express-and-babel-e2a53994ade but when I run the server I'm getting the following error:
Failed to load resource: the server responded with a status of 404
(Not Found) localhost/:1
Refused to execute script from
'http://localhost:3000/dist/bundle.js' because its MIME type
('text/html') is not executable, and strict MIME type checking is
enabled.
I have been searching this error for two days now and I haven't find a solution. I think the problem is that the bundle.js is not being created by webpack, I would like to now why is this happening
My project directory is the following:
My config webpack file:
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: './client/index.js',
output: {
path: __dirname,
filename: 'bundle.js',
publicPath: '/client/assets/'
},
module: {
loaders: [
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
include: path.join(__dirname, 'client'),
exclude: /node_modules/,
query: {
presets: ['es2015', 'react', 'stage-0']
}
},
{
test: /\.css$/,
loader: 'css-loader'
}
]
},
};
server.js, where I create the express instance:
const path = require('path')
const express = require('express')
module.exports = {
app: function () {
const app = express();
const indexPath = path.join(__dirname, 'indexDep.html');
const publicPath = express.static(path.join(__dirname, '../dist'));
app.use('/dist', publicPath);
app.get('/', function (_, res) { res.sendFile(indexPath) });
return app;
}
}
And app.js, where I'm running the server:
const Server = require('./server.js')
const port = (process.env.PORT || 3000)
const app = Server.app()
if (process.env.NODE_ENV !== 'production') {
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const config = require('../webpack.dev.config.js')
const compiler = webpack(config)
app.use(webpackHotMiddleware(compiler))
app.use(webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: config.output.publicPathdist
}))
}
app.listen(port)
console.log(`Listening at http://localhost:${port}`)
Try this:
// server.js
"use strict"
const path = require('path')
const express = require('express')
module.exports = {
app(init) {
const app = express()
const indexPath = path.join(__dirname, 'indexDep.html')
const publicPath = express.static(path.join(__dirname, '../dist'))
if (init != null) init(app)
app.use('/dist', publicPath)
app.get('/', function (_, res) { res.sendFile(indexPath) })
return app
},
}
// app.js
const Server = require('./server.js')
const port = (process.env.PORT || 3000)
Server.app(app => {
if (process.env.NODE_ENV !== 'production') {
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const config = require('../webpack.dev.config.js')
const compiler = webpack(config)
app.use(webpackHotMiddleware(compiler))
app.use(webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: config.output.publicPathdist
}))
}
})
.listen(port)
console.log(`Listening at http://localhost:${port}`)
Specifically, what this does is two-fold:
It punts your initialization to before Express finally reads its catch-all routes for /dist and /. If you add the middleware after, you'll never see it set up in the first place.
It retains most of your other logic, without moving a lot of code. Closures are useful for that kind of thing, keeping logic where it belongs while still allowing others to let you hook into their logic.
I configured webpack dev middleware, when I go to index page / all works fine, otherwise page Not Found, how to make work dev server for all paths ?
const Koa = require('koa');
const webpack = require('webpack');
const devMiddleware = require('koa-webpack-dev-middleware')
const path = require('path');
const fs = require('fs');
const PORT = 3000;
const app = new Koa();
const config = require('./webpack.config');
const compiler = webpack(config);
app.use(devMiddleware(compiler, {
publicPath: config.output.publicPath,
historyApiFallback: true,
stats: { colors: true },
}));
app.listen(PORT, function () {
console.log(`Dev Server port: "${3000}"`);
});
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
},
devtool: 'inline-source-map',
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
})
],
module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
}
]
}
}