How can I use Express.js with webpack? - javascript

I'm trying to set up a webpack server with Express.
When I use a simple script, such as the following:
document.getElementById('testing').innerHTML = "It's a test";
if (module.hot) {
module.hot.accept();
}
The server works fine, both from the same machine and from other devices in the same network.
However, when I try to require Express, it breaks with 25 errors.
Here's what I've got:
webpack.config.js
const path = require('path');
module.exports = {
entry: './app/serverTest.js',
mode: 'development',
output: {
filename: 'bundled.js',
path: path.resolve(__dirname, 'app')
},
devServer: {
before: (app, server) => {
server._watch('./app/**/*.html');
},
contentBase: path.join(__dirname, 'app'),
hot: true,
port: 4000,
host: '0.0.0.0'
},
}
serverTest.js
let express = require('express');
let app = express();
alert('This is a test');
I'm not even using the Express code. Just by requiring it, I get errors.
Here's the VSCode console logging: https://justpaste.it/342o0 (external link because it's very long)

Related

Webpack building the wrong file?

So I've a bug I've been chasing all day, and I've narrowed it down to my webpack config (I think).
I run my app locally using webpack server and index.html is displayed correctly (with the relevant script file).
I build my project locally, right-click index.html and open with live-server, and index.html is displayed correctly
I upload my files to my server, get Express to return index.html, and it returns index.html (I can tell because the script tag refers to index.js and the title tab says home), but the content is that of admin.html
Deleting the contents of index.html on the server to a simple page confirms (imo) that it isn't an issue of Express serving the wrong file
So it must be a webpack issue, right?
What I don't understand is why webpack server and live server display the content correctly, but the (apparently) same file doesn't in production. I probably don't have the correct webpack.prod.js config settings (they're basically empty), but I'm not experienced enough to spot the issue, so would appreciate if someone has the time to look
My file structure locally:
|-dist
|
|-src
| |-- assets
| |-- css
| |-- js
| |-- admin.html
| |-- index.html
|
|-webpack.common.js
|-webpack.dev.js
|-webpack.prod.js
|-package.json
|-// more config files
// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/js/controllers/indexController.js',
admin: './src/js/controllers/adminController.js'
},
output: {
filename: '[name].bundle.[chunkhash].js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
module: {
rules: [
{
test:/\.css$/i,
use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
test: /\.js$/i,
use: ['babel-loader'],
exclude: /node_modules/,
},
{
test: /\.(png|svg|jpg|jpeg|gif|webp)$/i,
type: 'asset/resource'
},
]
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
chunks: ['index']
}),
new HtmlWebpackPlugin({
filename: 'admin.html',
template: './src/admin.html',
chunks: ['admin']
})
]
}
// webpack.dev.js
const path = require('path');
const {merge} = require('webpack-merge');
const common = require('./webpack.common');
module.exports = merge(common, {
mode: "development",
devServer: {
static: {
directory: path.resolve(__dirname, 'dist'),
},
port: 4600,
open: {
app: {
name: 'chrome',
},
},
hot: true,
compress: true,
historyApiFallback: true,
watchFiles: ["src/**/*"]
},
});
// webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
});
*Edit I still think the server is sending the correct html file because the title and js src reference index, however the source now does look wrong (it has been correct in the past):
// var/www/my-site/express-app/public/html/index.html
<script defer="defer" src="./src/js/controllers/index.bundle.0bb3ac28e5969d907928.js"></script>
But I've no idea why the file was previously displaying another page's html (despite me removing that page, admin.html, entirely). It's no longer doing that, just complaining about the path to the file - which is progress.
Server file structure
// var/www/my-site/express-app
|-node_modules
|
|-public
| |-- assets
| |-- css
| |-- js
| |-- admin.html
| |-- index.html
|
|-package-lock.json
|-package.json
|-app.js
// app.js
const express = require('express');
const path = require('path');
const app = express();
const port = 3000;
app.use(express.static('public'));
app.get('/index', (req, res, next) => {
console.log('path:', path.join(__dirname, 'public', 'index.html'));
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
app.get('/', (req, res, next) => {
console.log('path:', path.join(__dirname, 'public', 'index.html'));
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
app.use((error, req, res, next) => {
res.status(500).json({msg: 'Please contact your web administrator'});
});
app.listen(port, () => console.log(`Listening on port ${port}`));

Uncaught SyntaxError: Cannot use import statement outside a module when using express

I am trying to deploy a website with a basic express server(inexperienced with it obviously) when I use a node dev server it works fine but when I use node server.js i get this error
Uncaught SyntaxError: Cannot use import statement outside a module
So I have a main.js with imports as follows:
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import { defaults as defaultControls } from 'ol/control';
I have my basic server.js
const express = require('express');
const path = require('path');
const port = process.env.PORT || 3003;
const app = express();
app.use(express.static(__dirname));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, './frontend/index.html'));
});
app.listen(port);
Start script
"start": "node server.js",
and webpack config
module.exports = {
entry: './main.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: './main.js'
},
devtool: 'source-map',
devServer: {
port: 3003,
clientLogLevel: 'none',
stats: 'errors-only'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new CopyPlugin([{from: 'data', to: 'data'}]),
new HtmlPlugin({
template: './frontend/index.html'
})
]
};
folder structure
frontend -index.html
-page2.html
main.js
package.json
webpack
...

Webpack on browser complains about require not defined

Here is my folder structure:
src/
└───public/
├───index.js
├───controllers/
├───css/
├───js/
├───models/
├───vendor/
└───views/
└───partials/
I know it's not the best folder structure, but it's one of my earlier projects, and I wanted to test webpack on it.
Anyways the controllers, js, vendor all contain javascript code.
My webpack.dev.config is on the same level as src:
const path = require("path");
const common = require("./webpack.common");
const {merge} = require("webpack-merge");
module.exports = merge(common, {
target: 'node',
mode: "development",
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
],
module: {
}
});
As you can see it merges from webpack.common.js:
const nodeExternals = require('webpack-node-externals');
module.exports = {
externals: [nodeExternals()],
entry: {
main: './src/index.js'
},
module: {
rules: [
{
test: /\.js$/,
}
]
}
}
For now I am hardcoding the location of the bundled js file in my HTML docs, but on the browser when I run this, I see the message Uncaught ReferenceError: require is not defined and I am not sure how to fix it.
Here is index.js:
const express = require('express');
const path = require('path');
const app = express();
const port = process.env.PORT || 8080;
const exphbs = require('express-handlebars');
const Datastore = require('nedb');
const db = new Datastore({
filename: path.join(__dirname, 'public/db/pfam.db'),
autoload: true
});
module.exports.db = db;
app.use(express.static(__dirname + "/public"));
app.set('views', path.join(__dirname, 'public/views'));
app.set('img', path.join(__dirname, 'public/img'));
app.set('js', path.join(__dirname, 'public/js'));
app.set('css', path.join(__dirname, 'public/css'));
app.set('controllers', path.join(__dirname, '/public/controllers'));
app.set('db', path.join(__dirname, '/public/db'));
app.engine('handlebars', exphbs({
defaultLayout: 'home',
layoutsDir: path.join(__dirname, '/public/views')
}))
app.set('view engine', 'handlebars');
app.use(require('./public/controllers'))
console.log(`listening on port ... ${port}`)
app.listen(port);
The reason you are getting Uncaught ReferenceError: require is not defined is because your bundles contains require keyword, which is undefined in the browser?
Why do they contain require?
Because you use nodeExternals from webpack-node-externals
From their docs:
All node modules will no longer be bundled but will be left as require('module').

Refused to execute script from bundle.js because its MIME type

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.

Express/React app works locally but not on Heroku

Update
Okay, so I updated the Procfile to bundle my components together
Procfile
web: npm run build-client && node server/index.js
But now it takes such a long time for my app to load because bundling takes a long time. Is there a better way to do this? This is a horrible user experience
...
And if nothing else, is there a way to render a static page right away that says:
Blame Heroku, not me
====== Original Context =======
My application works correctly with heroku local & localhost:8080, my view fails to render on deployment heroku open. From the console, I get this error message:
app.bundle.js:1 Uncaught SyntaxError: Unexpected token <
This particular bundle contains my React components. I used a codesplit with webpack to load in dependencies at different moments because I'm using a vr framework (aframe/three.js) on the front end and react. I don't understand why this is occurring if it works just fine locally.
index.html
I have codesplit some JS modules by aframe/three components inside of index.bundle. And all of my react components are inside of app.bundle
<head>
<meta charset="utf-8">
<title>Faceoff!</title>
<script src="./commons.js"></script>
<script src="./index.bundle.js"></script>
<script src="//cdn.rawgit.com/donmccurdy/aframe-extras/v3.13.1/dist/aframe-extras.min.js"></script>
<style> ... </style>
</head>
<body>
<div id="app"></div>
<script src="./app.bundle.js" defer></script>
</body>
webpack.config.js
'use strict'
const webpack = require('webpack')
const path = require('path')
const extractCommons = new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: 'commons.js'
})
const config = {
context: path.resolve(__dirname, 'client'),
entry: {
index: './index.js',
app: './app.jsx'
},
output: {
path: path.resolve(__dirname, 'public'),
filename: '[name].bundle.js'
},
devtool: 'source-map',
resolve: {
extensions: ['.js', '.jsx']
},
module: {
loaders: [
{
test: /jsx?$/,
include: path.resolve(__dirname, 'client'),
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
}
]
},
plugins: [
extractCommons
]
};
module.exports = config
index.js
The server-side code for the app. I have seen others catch their mistakes in this general location so I'll put this up for good measure.
'use strict'
const express = require('express');
const path = require('path');
const app = express();
const production = process.env.NODE_ENV === 'production';
const port = production ? process.env.PORT : 8080;
var publicPath = path.resolve(__dirname, '../public');
app.use(express.static(publicPath));
app.use('/', (req, res, send) => {
res.sendFile(path.resolve(__dirname, '..', 'index.html'))
})
app.listen(port, () => {
console.log(`Virtual Reality Enabled On Port ${port}`);
});
If your npm script build-client builds your webpack bundle. Reading your webpack.config.js tells me that the bundles will be in a directory called public and all your file names will have .bundle.js as a suffix. So you should change your Procfile to web: npm run build-client && node public/index.bundle.js

Categories