How to configure webpack for nodejs with server side rendering - node.js

I'm trying to setup Webpack to generate 2 bundles, one for server code with server side rendering and one for client code. So far the bundle seems to generate correctly but when I run the server code and it tries to render some of my React components it throws errors like this one:
ERROR in ./~/react-load-script/lib/index.js
Module build failed: ReferenceError: Unknown plugin "add-module-exports" specified in "/Users/alex/Development/muub/one/website/node_modules/react-load-script/.babelrc" at 0, attempted to resolve relative to "/Users/alex/Development/muub/one/website/node_modules/react-load-script"
at /Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/options/option-manager.js:180:17
at Array.map (native)
at Function.normalisePlugins (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/options/option-manager.js:158:20)
at OptionManager.mergeOptions (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/options/option-manager.js:234:36)
at OptionManager.init (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/options/option-manager.js:368:12)
at File.initOptions (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/index.js:212:65)
at new File (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/file/index.js:135:24)
at Pipeline.transform (/Users/alex/Development/muub/one/website/node_modules/babel-core/lib/transformation/pipeline.js:46:16)
at transpile (/Users/alex/Development/muub/one/website/node_modules/babel-loader/lib/index.js:46:20)
at Object.module.exports (/Users/alex/Development/muub/one/website/node_modules/babel-loader/lib/index.js:163:20)
# ./App/Containers/Publish/Payment/Payment.jsx 18:0-39
# ./App/Containers/Publish/Payment/index.js
# ./App/Containers/Publish/Publish.jsx
# ./App/Containers/Publish/index.js
# ./App/Routes/index.js
# ./App/Containers/App.jsx
# ./App/index.js
# multi webpack-hot-middleware/client react-hot-loader/patch ./App
There are more errors similar to this one but related with other 3rd party npm packages.
Here is my webpack server config:
const path = require('path');
const webpack = require('webpack');
const ExternalsPlugin = require('webpack2-externals-plugin');
let conf = {
devtool: 'source-map',
context: path.resolve(__dirname),
entry: [
path.resolve(__dirname, 'index.js')
],
target: 'node',
output: {
path: path.join(__dirname, 'build'),
pathinfo: true,
filename: 'server.js',
publicPath: '/public/',
libraryTarget: 'commonjs2'
},
resolve: {
modules: ['App', 'node_modules'],
extensions: ['.js', '.jsx']
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'css-loader/locals',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
localIdentName: '[name]__[local]__[hash:base64:5]'
}
},
'postcss-loader'
]
},
{
test: /\.(js|jsx)?$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new webpack.HotModuleReplacementPlugin(),
new ExternalsPlugin({
type: 'commonjs2',
include: path.join(__dirname, 'node_modules'),
exclude: [path.join(__dirname, 'node_modules', 'webpack/buildin'), path.join(__dirname, 'App')]
}),
new webpack.optimize.LimitChunkCountPlugin({maxChunks: 1}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
]
}
module.exports = conf;
What could I be doing wrong?

Related

Cannot find module "fs" - at webpackMissingModule

My server starts and runs correctly, but when I hit the URL in the browser it gives an error "cannot find module 'fs'".
I tried to setting:
target: 'node', but it starts another error
node: { fs: 'empty' }, but then it gives an error "cannot find exports"
"use strict";
const webpack = require('webpack');
const argv = require('minimist')(process.argv.slice(2));
const DEBUG = !argv.release;
const path = require('path');
var plugins = [
new webpack.optimize.CommonsChunkPlugin({
names: ['common', 'vendors'],
filename: '[name].js',
minChunks: Infinity
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': DEBUG ? '"development"' : '"production"',
"process.argv.verbose": !!DEBUG
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
jquery: "jquery"
})
].concat(DEBUG ? [] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
minimize: true,
compress: {
warnings: true
}
}),
new webpack.optimize.AggressiveMergingPlugin()
]);
module.exports = {
entry: {
app: path.join(__dirname, '..', 'app', 'app.js'),
vendors: [
'react',
'react-dom',
'react-bootstrap',
'react-router',
'alt',
'lodash',
'superagent',
'react-router-role-authorization',
'react-validation-decorator'
]
},
output: {
publicPath: '/js/',
path: './wwwroot/js/',
filename: '[name].js',
chunkFilename: "[id].[name].js"
},
context: path.join(__dirname, '..'),
plugins: plugins,
cache: DEBUG,
debug: DEBUG,
watch: DEBUG,
stats: {
colors: true
},
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx', '.json']
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel-loader']
},
{
test: /\.(less|css)$/,
loaders: ["style", "css", "less"]
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
loader: 'url-loader?limit=10000'
},
{
test: /\.(eot|ttf|wav|mp3|mp4)$/,
loader: 'file-loader'
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
node: {
net: 'mock',
dns: 'mock'
}
};
It should not give this error and work correctly.
I don't see any mention of the fs module in your posted webpack setup. So, my guess is that your output application (app.js?) is trying to require and use fs. Webpack is building a client-side, front-end application, one that will be loaded in the browser; fs is not available in the browser.
(Double-check and make sure you aren't trying to, for example, read and write files on the user's machine using fs inside your client-side application. That is not possible in a browser-based application. For an intro to the concept of web applications with a front end and back end, check out the article React App With Node Backend.)

How to use webpack to create a front end and a admin?

I am actually new on node.js. I am trying to create an app with admin and frontend using webpack and express. I have created an example app but now the problem is how I can create the app with the admin. Below I have shared my webpack config file
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: {
frontend: './src/index',
backend: './admin/index'
},
module: {
loaders: [
{
test: /\.js?$/, loader: 'babel', exclude: /node_modules/
},
{
test: /\.css$/,
loaders: [
'style?sourceMap',
'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
]
}
]
},
resolve: {
extensions: ['', '.js']
},
output: {
path: path.join(__dirname, '/public'),
publicPath: '/',
filename: 'bundle.js'
},
devServer: {
contentBase: './public',
hot: true
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
};
Webpack production configuration file
var config = require('./webpack.config.js');
var webpack = require('webpack');
config.plugins.push(
new webpack.DefinePlugin({
"process.env": {
"NODE_ENV": JSON.stringify("production")
}
})
);
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
);
Is there any easy solution or what I can do now?

Separate client and server in Webpack

Goal. Configuring app, which has: React, Webpack and MongoDB.
So, I've already setup Webpack for React and tried import Mongoose. The problem: React client-side and Mongoose - server-side, and because of that Webpack must have configurations for both. Using this answer: https://stackoverflow.com/a/37391247/7479176 I tried to configure Webpack. After that, I tried import Mongoose in my server.jsx file, but it didn't work.
Question. How to configure Webpack, so I can work with MongoDB?
Edited. I figured out how to rid of warnings (see Warnings):
output: {
filename: 'bundle.node.js',
libraryTarget: 'commonjs',
path: path.resolve(__dirname, 'dist')
},
externals: [
/^(?!\.|\/).+/i
],
But, when I added code into server.jsx (see server.jsx), it didn't log message in console.
Webpack configurations:
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = [
{
entry: {
index: './src/app/app.jsx'
},
devtool: 'inline-source-map',
devServer: {
port: 3000,
host: 'localhost',
historyApiFallback: true,
noInfo: false,
stats: 'minimal',
hot: true, // Tell the dev-server we're using HMR
contentBase: path.resolve(__dirname, './dist'),
publicPath: '/'
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(), // Enable HMR
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
},
{
entry: {
index: './src/server/server.jsx'
},
target: 'node',
output: {
filename: 'bundle.node.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
}
}
]
server.jsx:
import mongoose from 'mongoose'
import '../config/database.js'
mongoose.Promise = global.Promise
mongoose.connect(config.database)
// check connection
mongoose.connection.once('open', () => console.log('Connected to MongoDB'))
// check for db errors
mongoose.connection.on('error', err => console.log(err))
Warnings:
WARNING in ./node_modules/mongoose/lib/drivers/index.js
10:13-49 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
82:18-42 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
90:20-44 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
97:35-67 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/es6-promise/dist/es6-promise.js
Module not found: Error: Can't resolve 'vertx' in 'D:\Projects\JavaScriptProjects\pizzaday\node_modules\es6-promise\dist'
# ./node_modules/es6-promise/dist/es6-promise.js 131:20-30
# ./node_modules/mongodb/lib/mongo_client.js
# ./node_modules/mongodb/index.js
# ./node_modules/mongoose/lib/index.js
# ./node_modules/mongoose/index.js
# ./src/server/server.jsx
Solution. I used webpack-dev-middleware and webpack-hot-middleware with basic Express server. I tried launch MongoDB with React on webpack-dev-server and thats was main problem.
I made new server.js within separate folder following advice from Neil Lunn and setup basic Express server with middleware and split Webpack config into 3 separate files common, dev and prod.
This fragment of code in server.js helped me to run server and client together with Webpack which bonded everything together:
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}))
app.use(webpackHotMiddleware(compiler))
New Webpack config (webpack.common.js):
const webpack = require('webpack')
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
app: [
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true',
'./src/index.jsx'
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
inject: 'body'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}

karma Uncaught SyntaxError: Unexpected token export

I use karma + jasmine to write test cases for vue and webpack, and it once worked. But after I upgrade vue for 1 to 2, and update vue-loader accordingly, it starts to give error.
Now when I run karma start karma.config.js, it give me error like:
Chrome 53.0.2785 (Windows 7 0.0.0) ERROR
Uncaught SyntaxError: Unexpected token export
at test/index.js:8995
My karma.config.js is:
var webpackConf = require('./webpack.config.js')
delete webpackConf.entry
module.exports = function (config) {
config.set({
browsers: ['Chrome'],
frameworks: ['jasmine'],
reporters: ['progress', 'html'],
htmlReporter: {
outputFile: 'tests/unit-test.html',
// Optional
pageTitle: 'Unit Tests',
subPageTitle: 'A sample project description',
groupSuites: true,
useCompactStyle: true,
useLegacyStyle: true
},
// this is the entry file for all our tests.
files: [
{pattern: './test/index.js', watched: false},
],
// we will pass the entry file to webpack for bundling.
preprocessors: {
'./test/index.js': ['webpack']
},
// use the webpack config
webpack: webpackConf,
// avoid walls of useless text
webpackMiddleware: {
noInfo: true
},
singleRun: true,
plugins: [
'karma-chrome-launcher',
'karma-jasmine',
'karma-webpack',
'karma-htmlfile-reporter'
]
})
}
My webpack.config.js is:
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require('webpack');
module.exports = {
entry: ['webpack-hot-middleware/client','./index.js'],
output: {
path: path.resolve(__dirname, '../output/static'),
publicPath: '/',
//filename: '[name].[hash].js'
filename: 'main.js'
//chunkFilename: '[id].[chunkhash].js'
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js'
},
extensions: ['', '.js', '.vue']
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.js$/,
loader: 'babel?presets=es2015',
exclude: /node_modules/
},
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
]
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, 'index.html'),
inject: true
})
]
}
Looks like the es6 export syntax is not translated correctly. Also, I did not know where to take a look at the test/index.js:8995 because this is auto generated by webpack. The real index.js is quite simple, just 2 lines:
var testsContext = require.context('.', true, /\.spec\.js$/)
testsContext.keys().forEach(testsContext)
How to debug this and what can I do to solve the problem?

Sass loader not working in webpack

I am trying to get *.scss files to be supported in my webpack configuration but I keep getting the following error when I run the webpack build command:
ERROR in ./~/css-loader!./~/sass-loader!./app/styles.scss
Module build failed: TypeError: Cannot read property 'sections' of null
at new SourceMapConsumer (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/node_modules/source-map/lib/source-map/source-map-consumer.js:23:21)
at PreviousMap.consumer (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/previous-map.js:37:34)
at new Input (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/input.js:42:28)
at parse (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/parse.js:17:17)
at new LazyResult (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/lazy-result.js:54:47)
at Processor.process (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/processor.js:30:16)
at processCss (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/lib/processCss.js:168:24)
at Object.module.exports (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/lib/loader.js:21:15)
# ./app/styles.scss 4:14-117
I can't for the life of me figure out why. It's a very basic setup.
I have created a dropbox share with the bare minimum illustrating this:
https://www.dropbox.com/s/quobq29ngr38mhx/webpack.sass.test.zip?dl=0
Unzip this then run:
npm install
webpack
Here is my webpack.config.js file:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader'
}]
}
}
And the index.js entry file:
require('./styles.scss');
alert('foo bar baz');
And the styles.scss file:
body {
background-color: #000;
}
It appears to follow the recommendations of the sass-loader documentation site, but I can't get it to run.
:(
Information about my environment:
node - 0.12.4
npm - 2.10.1
os - OS X Yosemite
I have managed to get another workaround working that doesn't involve editing the css-loader libraries within my npm_modules directory (as per the answer by #chriserik).
If you add '?sourceMap' to the sass loader the css loader seems to handle the output.
Here is my updated configuration:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style!css!sass?sourceMap'
}]
}
}
P.S. I even expanded this test to include a compass-mixins include, and this worked too.
After having the same issue, I found this: https://github.com/webpack/css-loader/issues/84
Apparently, the solution for now is to manually modify lines 17-19 of /node_modules/css-loader/lib/loader.js with
if(map && typeof map !== "string") {
map = JSON.stringify(map);
}
This fixed the problem for me.
The problem is solved by setting source-map option to true (as seen in other answers).
But in case you find messy passing options in the query string there is an alternative;
for configuring the sass loader you can create a sassLoader property in the webpack config object:
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style!css!sass'
// loader: ExtractPlugin.extract('style', 'css!sass'),
}]
},
sassLoader: {
sourceMap: true
},
}

Resources