I'm trying to create a server-side rendering configuration for my React app with Webpack and Express.js and it almost works.
I managed to bundle my .jsx and sass, not using style-loader (which is client-only), but going with ExtractTextPlugin instead.
All was good, but then I tried to include css files into the bundle and on any css file, e.g. bootstrap.min.css, webpack chokes, although my SASS works fine. Here's the error message:
$ node_modules/webpack/bin/webpack.js --config ssr-webpack.config.js
Hash: 3e273674716344c7aa0b
Version: webpack 2.7.0
Time: 7982ms
Asset Size Chunks Chunk Names
server.js 3.82 MB 0 [emitted] [big] main
server.css 75.1 kB 0 [emitted] main
[4] ./src/services/translate.jsx 1.81 kB {0} [built]
[6] ./src/pages/Blog.jsx 19.1 kB {0} [built]
[7] ./src/pages/Post.jsx 10.5 kB {0} [built]
[8] ./src/pages/Layout.jsx 13 kB {0} [built]
[22] ./src/pages/Home.jsx 2.96 kB {0} [built]
[27] ./src/pages/posts/2017-10-21-1/index.jsx 9.71 kB {0} [optional] [built]
[28] ./src/pages/posts/2017-10-25-1/index.jsx 12.7 kB {0} [optional] [built]
[29] ./src/pages/posts/2017-11-01-1/index.jsx 21 kB {0} [optional] [built]
[30] ./src/pages/posts/2017-11-21-1/index.jsx 29.3 kB {0} [optional] [built]
[31] ./src/pages/posts/2017-11-30-1/index.jsx 24.2 kB {0} [optional] [built]
[39] ./src/server/app.jsx 4.02 kB {0} [built]
[41] ./src/pages/Blog.scss 41 bytes {0} [built]
[42] ./src/pages/Post.scss 41 bytes {0} [built]
[43] ./src/styles/style.scss 41 bytes {0} [built]
[57] ./src/pages/posts \.jsx 624 bytes {0} [built]
+ 49 hidden modules
Child extract-text-webpack-plugin:
[0] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
[1] ./~/css-loader?{"sourceMap":true}!./~/sass-loader/lib/loader.js?{"sourceMap":true}!./src/pages/Post.scss 450 bytes {0} [built]
Child extract-text-webpack-plugin:
[0] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
[1] ./~/css-loader?{"sourceMap":true}!./~/sass-loader/lib/loader.js?{"sourceMap":true}!./src/pages/Blog.scss 1.16 kB {0} [built]
Child extract-text-webpack-plugin:
[0] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
+ 1 hidden modules
Child extract-text-webpack-plugin:
[0] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
[1] ./~/css-loader?{"sourceMap":true}!./~/sass-loader/lib/loader.js?{"sourceMap":true}!./src/styles/style.scss 200 kB {0} [built]
/home/burkov/myproject/node_modules/bootstrap/dist/css/bootstrap.min.css:5
*//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:cont
SyntaxError: Unexpected token {
at Object.exports.runInThisContext (vm.js:73:16)
at Module._compile (module.js:543:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/home/burkov/myproject/dist/server.js:9084:18)
at __webpack_require__ (/home/burkov/myproject/dist/server.js:20:30)
npm ERR! Linux 4.9.0-5-amd64
npm ERR! argv "/home/burkov/.nvm/versions/node/v7.5.0/bin/node" "/home/burkov/.nvm/versions/node/v7.5.0/bin/npm" "run" "ssr"
npm ERR! node v7.5.0
npm ERR! npm v4.1.2
npm ERR! code ELIFECYCLE
npm ERR! [email protected] ssr: `node_modules/webpack/bin/webpack.js --config ssr-webpack.config.js && node dist/server.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] ssr script 'node_modules/webpack/bin/webpack.js --config ssr-webpack.config.js && node dist/server.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the burkov package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node_modules/webpack/bin/webpack.js --config ssr-webpack.config.js && node dist/server.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs burkov
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls burkov
npm ERR! There is likely additional logging output above.
npm ERR! Please include the following file with any support request:
npm ERR! /home/burkov/myproject/npm-debug.log
Here is my ssr-webpack.config.js configuration:
module.exports = {
target: 'node', // ignores built-in modules, creates output for node.js
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
entry: path.resolve(__dirname, 'src', 'server', 'app.jsx'),
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/',
filename: 'server.js'
},
resolve: {
modules: [path.join(__dirname, 'src'), path.join(__dirname, 'node_modules')]
},
plugins: [
new ExtractTextPlugin('server.css')
],
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react'],
plugins: ['transform-es2015-destructuring', 'transform-object-rest-spread']
}
},
{
test: /\.(scss|sass)$/,
use: ExtractTextPlugin.extract({
use: [
{ loader: 'css-loader', options: {sourceMap: true} },
{ loader: 'sass-loader', options: {sourceMap: true} }
]
})
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: [
{ loader: 'css-loader', options: {sourceMap: true} }
]
})
},
{
test: /\.(png|jpe?g|gif)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?emitFile=false'
},
{
test: /\.(eot|com|json|ttf|woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?emitFile=false'
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?emitFile=false'
}
]
}
};
Versions:
Node.js: 7.5.0
Webpack: ^2.2.0 (apparently, 2.7.0)
css-loader: ^0.28.4
OS: Debian 9
@BurkovBA can you create minimum reproducible test repo?
@evilebottnawi Thanks for reply!
I figured the cause of the problem. It turns out that due to the fact that I'm using nodeExternals:
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
to avoid inclusion of javascript from node_modules into the bundle, css that also resides in my node_modules (such as bootstrap.min.css) is also excluded and not passed to ExtractTextPlugin, but just required within the bundle with statements like:
/***/ })
/* 59 */
/***/ (function(module, exports) {
module.exports = require("bootstrap/dist/css/bootstrap.min.css");
}
Obviously, bootstrap.min.css is not a javascript code, so when node.js tries to execute this css as javascript, it returns an error on the very first line of css, which is an html { selector:
SyntaxError: Unexpected token {
I'm not sure, how to avoid this problem, though. I can't get rid of nodeExternals, cause without them javascript breaks, but I also need to bundle css from node_modules.
@BurkovBA very strange, maybe problem in webpack, tomorrow i will investigate this, also minimum reproducible test repo will help me to do this faster.
@evilebottnawi It's not exactly minimal, but this code is a part of my personal blog's repo: https://github.com/BurkovBA/BurkovBA.github.io
Take a look into package.json. It contains ssr script for building server-side, so you can run npm run ssr to reproduce the bug.
ssr-webpack.config.js in the repo's root is used for building Server-Side Rendered bundle and put it into /dist folder of the repo.
The server's code is in /src/server folder.
Thanks for your help, @evilebottnawi! If anything in my codebase is unclear, don't hesitate to ask me.
@evilebottnawi
Hiya! I think, I solved the problem with inclusion of css files into the bundle.
I should have read the webpack-node-externals documentation more carefully. They suggest that you use a regex for whitelisting non-javascript assets served from node_modules, so that they are not excluded from the bundle:
...
nodeExternals({
// load non-javascript files with extensions, presumably via loaders
whitelist: [/\.(?!(?:jsx?|json)$).{1,5}$/i],
}),
...
I added it and it works like a charm, although even with explanation I barely understand, how it excludes javascript.
Thanks again for your willingness to help!
@BurkovBA Great! Can you create improve docs (PR)?
Hi, @evilebottnawi!
Sure, I will do a PR.
Should I add an example of my configuration of Server-Side Rendering with CSS-loader to https://github.com/webpack-contrib/css-loader#examples section of README.md and explain in details what line does what?
@BurkovBA Will be great!
@evilebottnawi
Sent the PR with a detailed description of setup and example webpack configuration relevant to css-loader.
Cheers!
Most helpful comment
@evilebottnawi
Hiya! I think, I solved the problem with inclusion of css files into the bundle.
I should have read the webpack-node-externals documentation more carefully. They suggest that you use a regex for whitelisting non-javascript assets served from
node_modules, so that they are not excluded from the bundle:I added it and it works like a charm, although even with explanation I barely understand, how it excludes javascript.
Thanks again for your willingness to help!