catamphetamine / universal-webpack

Isomorphic Webpack: both on client and server

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

import token from .scss file illegal

ngoctranfire opened this issue · comments

commented

I keep running into this error. This is my start-server.js file.

const { server } = require('universal-webpack');
const settings = require('./config/universal-webpack-settings');
const serverConfig = require('./config/webpack.config.server');

server(serverConfig, settings);

This is my settings file:

const { DIST, SRC } = require('./paths');
const path = require('path');

module.exports = {
  server:
  {
    input: path.join(SRC, 'server-entry.js'),
    output: path.join(DIST, 'server.js')
  }
};

This is my server-entry.js file. If i comment out the require('./server/server.js'), and the setupServer() part, it will work flawlessly, but I need that setupServer part.

require('babel-polyfill');
import express from 'express';
import SwaggerExpress from 'swagger-express-mw';

import {SWAGGER} from './config/paths';
import './config/environment';

function startServer (parameters) {
  const app = express();

  var config = {
    appRoot: SWAGGER
  };
  SwaggerExpress.create(config, (err, swaggerExpress) => {
    if (err) {
      throw err;
    }
    const setupServer = require('./server/server');
    // This installs the middleware
    swaggerExpress.register(app);
    setupServer(app);

    app.listen(process.env.PORT, () => {
      console.log(`listening at http://localhost:${process.env.PORT}`); // eslint-disable-line
    });

  });
}

module.exports = startServer;

Here is my setupSever.js file

import React from 'react';
import { renderToString } from 'react-dom/server';
import express from 'express';
import debug from 'debug';
import morgan from 'morgan';

import compression from 'compression';
import Error500 from './templates/Error500';
import { routingApp, setRoutes } from './router';
import initFirebase from './api/firebase';

const setUpServer = (server, assets) => {
  const log = debug('preact-lego.js, setting up server.js');
  log('starting');
  initFirebase();

  server.set('etag', true);
  server.use((req, res, next) => {
    res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.header('Pragma', 'no-cache');
    res.header('Expires', 0);
    next();
  });
  server.use(morgan('combined'));
  server.use(compression());
  server.enable('view cache');
  server.enable('strict routing');

  Object.assign(express.response, {
    renderPageToString(page) {
      return `<!doctype html>${renderToString(page)}`;
    },
    render500(e) {
      console.log(" This is a 500 error", e);
      log('render500', e);
      this.status(500).send(this.renderPageToString(<Error500 />));
    }
  });
  server.use('/', routingApp);

  setRoutes(assets);
};
export default setUpServer;
/node_modules/react-toolbox/lib/ripple/theme.scss:1
(function (exports, require, module, __filename, __dirname) { @import "../colors";
                                                                                                 ^
SyntaxError: Unexpected token ILLEGAL
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:511:25)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:456:32)
    at tryModuleLoad (module.js:415:12)
    at Function.Module._load (module.js:407:3)
    at Module.require (module.js:466:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (.........../node_modules/react-toolbox/lib/ripple/index.js:13:14)
    at Module._compile (module.js:541:32)
SyntaxError: Unexpected token ILLEGAL
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:511:25)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:456:32)
    at tryModuleLoad (module.js:415:12)
    at Function.Module._load (module.js:407:3)
    at Module.require (module.js:466:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (...../node_modules/react-toolbox/lib/ripple/index.js:13:14)
    at Module._compile (module.js:541:32)

Also, this is my package.json file and I'm currently running npm run start:dev:

 "build:dev": "NODE_CONFIG_DIR=src/config NODE_ENV=development webpack-dev-server --hot --inline --config src/config/webpack.config.dev.js --port 3001",
    "build:server": "NODE_CONFIG_DIR=src/config webpack --config src/config/webpack.config.server.js",
    "start": "NODE_CONFIG_DIR=src/config NODE_ENV=production node compiled/server.js",
    "start:dev": "NODE_CONFIG_DIR=src/config npm-run-all --parallel build:dev build:server development-server",
    "development-server": "NODE_CONFIG_DIR=src/config nodemon src/start-server.js --watch compiled/dist --ignore src/app --exec babel-node",
    "prep-server": "universal-webpack --settings src/config/universal-webpack-settings.js",

Can you help me figure out what is going on?

commented

Also, I know in webpack-isomorphic-tools, the server passes down the assets to us. How does the universal-webpack pass down the assets to us so that I have access to it for server-side rendering?

const serverConfig = require('./config/webpack.config.server');

This is not what the README says:

// configuration.context and configuration.output.path are used
import configuration from '../webpack.config'

const setupServer = require('./server/server');

Why do you do that?
The README doesn't tell you do that.

commented

Oh that is not my actual server file. If you take a look that is just a function that adds on middlewares to my initialized server

commented

You can take a look at my setupServer.js file to see what I mean.

Well, the error says about /node_modules/react-toolbox/lib/ripple/theme.scss:1 which is in node_modules so I guess your webpack css loader configuration is wrong due to excluding node_modules or whatever else.

commented

Basically, I think you misunderstood because I had a bad naming convention. I imported that ./server/server.js file, but all that file is just a setup configurations file for my server.

If I take tha tout, it would look something like this:

require('babel-polyfill');
import SwaggerExpress from 'swagger-express-mw';

import {SWAGGER} from './config/paths';
import './config/environment';

import React from 'react';
import { renderToString } from 'react-dom/server';
import express from 'express';
import debug from 'debug';
import morgan from 'morgan';

import compression from 'compression';
import Error500 from './server/templates/Error500';
import { routingApp, setRoutes } from './server/router';
import initFirebase from './server/api/firebase';

const setUpServer = (server, assets) => {
const log = debug('project-landing:server.js, setting up server.js');
log('starting');
initFirebase();

server.set('etag', true);
server.use((req, res, next) => {
res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.header('Pragma', 'no-cache');
res.header('Expires', 0);
next();
});
server.use(morgan('combined'));
server.use(compression());
server.enable('view cache');
server.enable('strict routing');

Object.assign(express.response, {
renderPageToString(page) {
return <!doctype html>${renderToString(page)};
},
render500(e) {
console.log(" This is a 500 error", e);
log('render500', e);
this.status(500).send(this.renderPageToString());
}
});
server.use('/', routingApp);

setRoutes(assets);
};

function startServer (parameters) {
// console.log("These are my parameters", parameters.chunks());

var config = {
appRoot: SWAGGER
};
SwaggerExpress.create(config, (err, swaggerExpress) => {
if (err) {
throw err;
}
const app = express();
// This installs the middleware
swaggerExpress.register(app);
setUpServer(app, parameters.chunks());

app.listen(process.env.PORT, () => {
  console.log(`listening at http://localhost:${process.env.PORT}`); // eslint-disable-line
});

});
}

module.exports = startServer;

commented

Can I show you my webpack so you can tell me if what I'm doing is correct?

Post it

commented

This is my webpack:

const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const cssnano = require('cssnano');

const { SRC, DIST, NODE_MODULES, ROOT } = require('./paths');

module.exports = {
  context: ROOT,
  devtool: 'source-map',
  output: {
    path: DIST,
    filename: '[name].js',
    publicPath: '/'
  },
  plugins: [
    new ExtractTextPlugin('[name].css'),
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        PORT: JSON.stringify(process.env.PORT),
        DEBUG: JSON.stringify(process.env.DEBUG),
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
      }
    }),
  ],
  resolve: {
    modulesDirectories: [SRC, NODE_MODULES],
    extensions: ['', '.js', '.jsx', '.scss', '.css']
  },
  sassLoader: {
    data: '@import "theme/styles.scss";',
    includePaths: [SRC]
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        include: [/src/],
        loader: 'babel'
      },
      {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract('style', [
          'css?modules&importLoaders=1&sourceMap&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
          'postcss',
          'sass?sourceMap&outputStyle=expanded'])
      },
      {
        test: /\.svg$/,
        loaders: ['svg-inline']
      }

    ]
  },
  postcss: [
    cssnano({
      autoprefixer: {
        browsers: [
          'safari 9',
          'ie 10-11',
          'last 2 Chrome versions',
          'last 2 Firefox versions',
          'edge 13',
          'ios_saf 9.0-9.2',
          'ie_mob 11',
          'Android >= 4'
        ],
        cascade: false,
        add: true,
        remove: true
      },
      safe: true
    })
  ]
};

  sassLoader: {
    data: '@import "theme/styles.scss";',
    includePaths: [SRC]
  },
commented

What is exactly wrong there? If I remove it, I would still get the same error

commented

The sass-loader, I thought is just for adding onto every sass file import I have the needed configurations

Then I don't know.
Your webpack configuration is complex.
The cause of the error is most likely there.

commented

Hmm alright then. Darn. That's super weird that it only happens when I have the stuff I use in my setupServer() function

You can try simplifying your code by removing as many lines of code as can be removed, and then you might get to the source of the error.

commented

Ahh, so I figured out the error, but not really sure what the fix should be. In one of my file imports, I import the following file:

import React from 'react';
import { Route, IndexRoute, Link } from 'react-router';
import debug from 'debug';

import NotFound from './containers/NotFound/NotFound';
import Home from './containers/home/home';
import LoginPage from './landing/containers/loginPage';
import SignupPage from './landing/containers/signupPage';

import Welcome from './dashboard/containers/home/welcome';
import SeekFeedback from './dashboard/containers/seek-feedback';
import GiveFeedback from './dashboard/containers/give-feedback';
import MyResume from './dashboard/containers/my-resume';
import Profile from './dashboard/containers/profile';
import GetStarted from './dashboard/containers/get-started';

debug('lego:routes');

const siteTitle = 'Project Landing';

export const routes = {
  homepage: {
    path: '/',
    label: 'Welcome to project Landing',
    title: `${siteTitle} - Welcome to Project Landing`,
    component: Welcome
  },
  login: {
    path: '/login',
    label: 'Login to Project Landing',
    title: `${siteTitle} - Login`,
    component: LoginPage
  },
  signup: {
    path: '/signup',
    label: 'Signup to Start',
    title: `${siteTitle} - Signup`,
    component: SignupPage
  },
  getStarted: {
    path: '/get-started',
    label: 'Get Started',
    title: `${siteTitle} - Get Started`,
    component: GetStarted
  },
  profile: {
    path: '/profile',
    label: 'Profile',
    title: `${siteTitle} - Profile`,
    component: Profile
  },
  myResume: {
    path: '/my-resume',
    label: 'My Resume',
    title: `${siteTitle} - My Resume`,
    component: MyResume
  },
  seekFeedback: {
    path: '/seek-feedback',
    label: 'Seek Feedback',
    title: `${siteTitle} - Seek Feedback`,
    component: SeekFeedback
  },
  giveFeedback: {
    path: '/give-feedback',
    label: 'Give Feedback',
    title: `${siteTitle} - Give Feedback`,
    component: GiveFeedback
  }

};

const indexRoute = (route) => Object.assign({}, route, { path: null });

export const LinkHelper = ({ to, ...props }) => {
  if (!routes[to]) throw new Error(`Route to '${to}' not found`);
  return (
    <Link to={ routes[to].path } { ...props }>
      { props.children || routes[to].label }
    </Link>
  );
};

export function makeRoutes() {
  return (
    <Route path="/" component={ Home }>
      <IndexRoute { ...indexRoute(routes.homepage) } />
      <Route { ...routes.login } />
      <Route { ...routes.signup } />
      <Route { ...routes.getStarted} />
      <Route { ...routes.profile} />
      <Route { ...routes.myResume} />
      <Route { ...routes.giveFeedback} />
      <Route { ...routes.seekFeedback} />
      <Route path="*" title ={`${siteTitle} - Page Not Found`} component={ NotFound} />
    </Route>
  );
}

Apparently.... It seems that if my server side does any server side rendering and it imports any react-elements (which eventually uses react-toolbox), it will just fail and throw that error. Most likely, I think the reason is that my react-toolbox hasn't been required at the time yet and exposed.

You can try requiring all react components immediately at the top.

commented

You mean in my server-entry.js file right?

For example