catamphetamine / universal-webpack

Isomorphic Webpack: both on client and server

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error: [universal-webpack] Your server source file must export a function

aight8 opened this issue · comments

I try to start the server build server like following:

nodemon -L ./start-server.js --exec babel-node --watch ./build/server

The server.js (built with webpack located in ./build/server/server.js) have a special webpack exported format and start-server.js and universal-webpack/server.js run in a normal node environment and tries to include the buit server.js here

https://github.com/halt-hammerzeit/universal-webpack/blob/master/source/server.js#L41

The result is that the "starter" variable become following:

[ 0, 1 ]

What did I miss?

I didn't understand what is your situation.
Post your ./start-server.js, server.js.

start-server.js

import 'source-map-support/register';

import { server } from 'universal-webpack';
import settings from './universal-webpack-settings';
import configuration from './webpack.config';

server(configuration, settings);

server.jsx (it's currently just a test - but the exported function is there anyway)

import { renderToString } from 'react-dom/server'
import path from 'path'
import http from 'http'
import express from 'express'
import http_proxy from 'http-proxy'
import { match, RouterContext } from 'react-router'
import routes from './pages/internal/routes'
import store from 'lib/store'
import { Provider } from 'react-redux'

export default function(parameters) {
  // Create HTTP server
  const app = new express();
  const server = new http.Server(app);

  // React application rendering
  app.use((req, res) => {
    // Math current URL to the corresponding React page
    match(routes, req.originalUrl).then((error, redirectLocation, renderProps) => {
      if (error) {
        res.status(500);
        return res.send('Server error');
      }

      let page = (
        <Provider store={store}>
          <RouterContext {...renderProps} />
        </Provider>
      );

      res.status(200);
      res.send('<!doctype html>' + '\n' + renderToString(<Html>{page}</Html>));
    })
  });

  // Start the HTTP server
  server.listen(4000)
};

Execution:

babel-node ./node_modules/.bin/webpack --watch --config ./webpack.config.server.js --display-error-details
nodemon -L ./start-server.js --exec babel-node --watch ./build/server

Well, it does export a function.
You can post your ./build/server too so that I could have a look on the generated code.

Input (I shrink it since I have the same effect whit this easy statement):

export default function(parameters) {
};

Output:

module.exports =
exports.ids = [0,1];
exports.modules = [
/* 0 */
/*!************************!*\
  !*** ./src/server.jsx ***!
  \************************/
/***/ function(module, exports) {

    "use strict";

    Object.defineProperty(exports, "__esModule", {
      value: true
    });

    exports.default = function (parameters) {};

    ;

/***/ }
];;
//# sourceMappingURL=server.js.map

Error stack:

Error: [universal-webpack] Your server source file must export a function
    at xxx/node_modules/universal-webpack/source/server.js:55:9
    at run (xxx/node_modules/babel-polyfill/node_modules/core-js/modules/es6.promise.js:89:22)
    at xxx/node_modules/babel-polyfill/node_modules/core-js/modules/es6.promise.js:102:28
    at flush (xxx/node_modules/babel-polyfill/node_modules/core-js/modules/_microtask.js:18:9)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickDomainCallback (internal/process/next_tick.js:122:9)

[nodemon] app crashed - waiting for file changes before starting...

Error Stack:

Error: [universal-webpack] Your server source file must export a function
    at /xxx/node_modules/universal-webpack/source/server.js:55:9
    at run (/xxx/node_modules/babel-polyfill/node_modules/core-js/modules/es6.promise.js:89:22)
    at /xxx/node_modules/babel-polyfill/node_modules/core-js/modules/es6.promise.js:102:28
    at flush (/xxx/node_modules/babel-polyfill/node_modules/core-js/modules/_microtask.js:18:9)
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickDomainCallback (internal/process/next_tick.js:122:9)

[nodemon] app crashed - waiting for file changes before starting...

Well, yes, it says clearly that module.exports = [0,1]; which means it exports an array, not a function.
It should have just compiled that file but instead it changed its exports to [0,1].
It seems that it compiles server.jsx in a wrong way.
Why is it jsx anyway?
It looks like if webpack loaders are messed up for your .jsx extension.
It may be an issue in your webpack config.

You may post you server-side webpack config.

I try to solve that in a way and come back with a feedback.

I currently use es6 in webpack with the following:

"watch:server": "babel-node ./node_modules/.bin/webpack --watch --config ./webpack.config.server.js --display-error-details",

It could be the problem is somewhere there.

btw: jsx = es6 with possible jsx sugar. It's just more explicit that it must be transcompiled with babel.

You still haven't posted your ./webpack.config.server.js

_webpack.config.server:_

import { server_configuration } from 'universal-webpack';
import settings from './universal-webpack-settings.js';
import configuration from './webpack.config.js';

export default server_configuration(configuration, settings);

This config will be generated (test property seems to be empty object in json because it's a regex object):

{
   "context": "xxx/frontend",
   "entry": {
      "server": "./src/server.jsx"
   },
   "output": {
      "path": "xxx/frontend/build/server",
      "publicPath": "http://127.0.0.1:8080/assets/",
      "filename": "[name].js",
      "chunkFilename": "[name].js",
      "sourceMapFilename": "[file].map",
      "libraryTarget": "commonjs2",
      "pathinfo": true
   },
   "resolve": {
      "extensions": [
         "",
         ".js",
         ".jsx"
      ],
      "alias": {
         "actions": "xxx/frontend/src/actions",
         "app": "xxx/frontend/src/app",
         "lib": "xxx/frontend/src/lib",
         "pages": "xxx/frontend/src/pages",
         "reducers": "xxx/frontend/src/reducers",
         "sagas": "xxx/frontend/src/sagas",
         "scss": "xxx/frontend/src/scss",
         "selectors": "xxx/frontend/src/selectors",
         "foundation": "xxx/frontend/node_modules/foundation-sites/js"
      }
   },
   "module": {
      "loaders": [
         {
            "test": {},
            "loader": "xxx/frontend/node_modules/extract-text-webpack-plugin/loader.js?{\"remove\":true,\"id\":1}!css!sass"
         },
         {
            "test": {},
            "loaders": [
               "fake-style-loader",
               "css",
               "sass"
            ],
            "exclude": [
               "xxx/frontend/src/scss/app.scss"
            ]
         },
         {
            "test": {},
            "loaders": [
               "fake-style-loader",
               "css",
               "less"
            ]
         },
         {
            "test": {},
            "include": [
               "xxx/frontend/src",
               "xxx/frontend/node_modules/lodash-es"
            ],
            "loaders": [
               "babel"
            ]
         },
         {
            "test": {},
            "loaders": [
               "fake-style-loader",
               "css"
            ]
         },
         {
            "test": {},
            "loaders": [
               "url?limit=5000&name=rsrc/img/[name].[ext]&mimeType=image/[ext]",
               "image-webpack?{progressive:true, optimizationLevel: 7, interlaced: false, pngquant:{quality: \"25-80\", speed: 10}}"
            ]
         },
         {
            "test": {},
            "loaders": [
               "file"
            ]
         }
      ]
   },
   "sassLoader": {
      "includePaths": [
         "xxx/frontend/src/scss/shared"
      ]
   },
   "progress": true,
   "plugins": [
      {
         "chunkNames": "vendor",
         "ident": "xxx/frontend/node_modules/webpack/lib/optimize/CommonsChunkPlugin.js0"
      },
      {
         "definitions": {
            "React": "react",
            "Immutable": "seamless-immutable",
            "pureRender": "pure-render-decorator",
            "autobind": "autobind-decorator"
         }
      },
      {
         "filename": "[name].css",
         "options": {
            "allChunks": true
         },
         "id": 1
      },
      {
         "options": {
            "maxChunks": 1
         }
      }
   ],
   "target": "node",
   "devtool": "source-map",
   "externals": [
      null
   ]
}

Oh, I meant post your ./webpack.config.js

webpack.config.js:

import path from 'path';
import process from 'process';
import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
const extractStyle = new ExtractTextPlugin('[name].css', { allChunks: true });

const root_folder = path.resolve(__dirname, '..');
const src_folder = path.resolve(__dirname, 'src');

const alias = {
  actions: path.resolve(src_folder, 'actions'),
  app: path.resolve(src_folder, 'app'),
  lib: path.resolve(src_folder, 'lib'),
  pages: path.resolve(src_folder, 'pages'),
  reducers: path.resolve(src_folder, 'reducers'),
  sagas: path.resolve(src_folder, 'sagas'),
  scss: path.resolve(src_folder, 'scss'),
  selectors: path.resolve(src_folder, 'selectors'),
  foundation: path.resolve(__dirname, 'node_modules', 'foundation-sites', 'js'),
};

let plugins = [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
  }),
  new webpack.ProvidePlugin({
    React: 'react',
    Immutable: 'seamless-immutable',
    pureRender: 'pure-render-decorator',
    autobind: 'autobind-decorator',
  }),
  extractStyle,
];

if (process.env.NODE_ENV === 'production') {
  plugins.push(new webpack.optimize.UglifyJsPlugin({
    compress: {
      warnings: false,
    },
  }));
}

export default {
  context: __dirname,
  entry: {
    app: path.resolve(src_folder, 'app.jsx'),
    vendor: [
      'babel-polyfill',
      'react-dom',
      'react',
      'redux',
      'redux-saga',
      'moment',
      'seamless-immutable',
      'redux-form',
    ],
  },
  output: {
    path: path.resolve(root_folder, 'public', 'assets'),
    //publicPath: '/assets/',
    publicPath: 'http://127.0.0.1:8080/assets/',
    filename: '[name].bundle.js',
    chunkFilename: '[name].[hash].chunk.js',
    sourceMapFilename: '[file].map',
  },
  resolve: {
    extensions: ['', '.js', '.jsx'],
    //root: path.resolve(__dirname, 'src'), // webpack 1
    alias,
    /*modules: [ // webpack 2
      path.resolve(__dirname, 'app'),
      'node_modules',
    ],*/
  },
  module: {
    loaders: [
      {
        test: /app\.scss$/,
        loader: extractStyle.extract(['css', 'sass']),
      },
      {
        test: /\.scss$/,
        loaders: ['style', 'css', 'sass'],
        exclude: [path.resolve(__dirname, 'src', 'scss', 'app.scss')],
      },
      {
        test: /\.less$/,
        loaders: ['style', 'css', 'less'],
      },
      {
        test: /\.jsx?$/,
        loader: 'babel',
        include: [
          path.resolve(__dirname, 'src'),
          path.resolve(__dirname, 'node_modules', 'lodash-es'),
        ],
      },
      {
        test: /\.css$/,
        loaders: ['style', 'css'],
      },
      {
        test: /\.(ico|gif|png|jpe?g)$/,
        loaders: [
          'url?limit=5000&name=rsrc/img/[name].[ext]&mimeType=image/[ext]',
          'image-webpack?{progressive:true, optimizationLevel: 7, interlaced: false, pngquant:{quality: "25-80", speed: 10}}'
        ]
      },
      {
        test: /\.(svg|ttf|eot|woff(2)?)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        loaders: ['file'],
      }
    ]
  },
  sassLoader: {
    includePaths: [
      path.resolve(__dirname, 'src', 'scss', 'shared'),
    ],
  },
  progress: true,
  plugins,
};

You can try to remove all the unnecessary stuff from there.
E.g. remove:


  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
  }),
extractStyle

etc

I removed only the CommonsChunkPlugin and this error don't happen anymore. I have no idea why, don't know the webpack internals this deep today.

(but some others which I listed in the other issue again :))

So it seems to be the commons chunk plugin could be the problem. Can this library solve this somehow?

I released universal-webpack@0.1.16 whick removes CommonsChunkPlugin.
You may try it out.

The comparison is not correct, it don't remove any plugins now. It must check if the constructor.

return plugin!== _webpack2.default.HotModuleReplacementPlugin && plugin!== _webpack2.default.optimize.CommonsChunkPlugin;

should be:

return plugin.constructor !== _webpack2.default.HotModuleReplacementPlugin && plugin.constructor !== _webpack2.default.optimize.CommonsChunkPlugin;

Maybe a instanceof check do the job as well.

Oops, really.