admin管理员组

文章数量:1415653

I am trying to get my application to work in development mode with Node and Webpack-Dev-Server. When I serve up '/' I get back exactly what I intend. However, when I do '/test' I get 'no such file or directory'. I have read a lot of documentation on Webpack's website and React Router Training, none seem to really answer this issue. I want to be able to use browserHistory instead of hashHistory (I am still using React-Router v3).

package.json:

{
  "name": "boilerplate",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "clean": "rimraf dist",
    "build": "NODE_ENV=production npm run clean && webpack -p",
    "dev": "nodemon server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.15.3",
    "babel-core": "^6.7.2",
    "babel-loader": "^6.2.4",
    "babel-plugin-transform-class-properties": "^6.22.0",
    "babel-preset-env": "^1.1.8",
    "babel-preset-react": "^6.5.0",
    "css-loader": "^0.26.1",
    "express": "^4.14.0",
    "html-webpack-plugin": "^2.26.0",
    "react": "^15.4.1",
    "react-dom": "^15.4.1",
    "react-redux": "^4.4.1",
    "react-router": "^3.2.0",
    "redux": "^3.3.1",
    "redux-promise": "^0.5.3",
    "rimraf": "^2.5.4",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^3.8.1"
  },
  "devDependencies": {
    "nodemon": "^1.11.0",
    "webpack-dev-middleware": "^1.9.0",
    "webpack-dev-server": "^2.2.0-rc.0",
    "webpack-hot-middleware": "^2.20.0"
  }
}

webpack.config.js

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const VENDOR_LIBS = [
  'axios', 'react', 'redux', 'react-dom', 'react-redux',
  'react-router', 'redux-promise'
];

module.exports = {
  entry: {
    bundle: './client/src/index.js',
    vendor: VENDOR_LIBS
  },
  output: {
    chunkFilename: '[name].[chunkhash].js',
    path: path.join(__dirname, 'dist'),
    publicPath: '/'
  },
  module: {
    rules: [
      {
        use: 'babel-loader',
        test: /\.js$/,
        exclude: /node_modules/
      },
      {
        use: ['style-loader', 'css-loader'],
        test: /\.css$/
      },
      {
        test: /\.(jpe?g|png|gif|svg|)$/,
        use: [
          {
            loader: 'url-loader',
            options: {limit: 40000}
          },
          'image-webpack-loader'
        ]
      }
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      names: ['vendor', 'manifest']
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    }),
    new HtmlWebpackPlugin({
      template: './client/src/index.html'
    })
  ],
  devtool: 'inline-source-map',
  devServer: {
    contentBase: '/dist',
    historyApiFallback: true
  },
};

server.js:

const express = require('express');
const path = require('path');
const app = express();


if (process.env.NODE_ENV !== 'production') {
  app.use(express.static(path.join(__dirname, 'dist')));
  const webpack = require('webpack');
  const webpackDevMiddleware = require('webpack-dev-middleware');
  const config = require('./webpack.config.js');
  const piler = webpack(config);
  app.use(webpackDevMiddleware(piler, {
    publicPath: config.output.publicPath
  }));
} else {
  app.use(express.static('dist'));
}

app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});


app.listen(process.env.PORT || 3050, () => console.log('Listening'));

routes.js:

import React from 'react';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';

import App from './ponents/app';
import Home from './ponents/home';

const ponentRoutes = (
  <Route ponent={App} path='/'>
    <Route ponent={Home} path='/test' />
  </Route>
);

const Routes = () => {
  return <Router history={ browserHistory } routes={ ponentRoutes } />
};

export default Routes;

The App ponent renders a single div saying it loaded and same for the Home ponent. If you care to see the entire thing on Github, here is a link:

The main goal is to be able to load '/test' in dev mode without using hashHistory.

Wepback docs: /

I am trying to get my application to work in development mode with Node and Webpack-Dev-Server. When I serve up '/' I get back exactly what I intend. However, when I do '/test' I get 'no such file or directory'. I have read a lot of documentation on Webpack's website and React Router Training, none seem to really answer this issue. I want to be able to use browserHistory instead of hashHistory (I am still using React-Router v3).

package.json:

{
  "name": "boilerplate",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "clean": "rimraf dist",
    "build": "NODE_ENV=production npm run clean && webpack -p",
    "dev": "nodemon server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.15.3",
    "babel-core": "^6.7.2",
    "babel-loader": "^6.2.4",
    "babel-plugin-transform-class-properties": "^6.22.0",
    "babel-preset-env": "^1.1.8",
    "babel-preset-react": "^6.5.0",
    "css-loader": "^0.26.1",
    "express": "^4.14.0",
    "html-webpack-plugin": "^2.26.0",
    "react": "^15.4.1",
    "react-dom": "^15.4.1",
    "react-redux": "^4.4.1",
    "react-router": "^3.2.0",
    "redux": "^3.3.1",
    "redux-promise": "^0.5.3",
    "rimraf": "^2.5.4",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^3.8.1"
  },
  "devDependencies": {
    "nodemon": "^1.11.0",
    "webpack-dev-middleware": "^1.9.0",
    "webpack-dev-server": "^2.2.0-rc.0",
    "webpack-hot-middleware": "^2.20.0"
  }
}

webpack.config.js

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const VENDOR_LIBS = [
  'axios', 'react', 'redux', 'react-dom', 'react-redux',
  'react-router', 'redux-promise'
];

module.exports = {
  entry: {
    bundle: './client/src/index.js',
    vendor: VENDOR_LIBS
  },
  output: {
    chunkFilename: '[name].[chunkhash].js',
    path: path.join(__dirname, 'dist'),
    publicPath: '/'
  },
  module: {
    rules: [
      {
        use: 'babel-loader',
        test: /\.js$/,
        exclude: /node_modules/
      },
      {
        use: ['style-loader', 'css-loader'],
        test: /\.css$/
      },
      {
        test: /\.(jpe?g|png|gif|svg|)$/,
        use: [
          {
            loader: 'url-loader',
            options: {limit: 40000}
          },
          'image-webpack-loader'
        ]
      }
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      names: ['vendor', 'manifest']
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    }),
    new HtmlWebpackPlugin({
      template: './client/src/index.html'
    })
  ],
  devtool: 'inline-source-map',
  devServer: {
    contentBase: '/dist',
    historyApiFallback: true
  },
};

server.js:

const express = require('express');
const path = require('path');
const app = express();


if (process.env.NODE_ENV !== 'production') {
  app.use(express.static(path.join(__dirname, 'dist')));
  const webpack = require('webpack');
  const webpackDevMiddleware = require('webpack-dev-middleware');
  const config = require('./webpack.config.js');
  const piler = webpack(config);
  app.use(webpackDevMiddleware(piler, {
    publicPath: config.output.publicPath
  }));
} else {
  app.use(express.static('dist'));
}

app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});


app.listen(process.env.PORT || 3050, () => console.log('Listening'));

routes.js:

import React from 'react';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';

import App from './ponents/app';
import Home from './ponents/home';

const ponentRoutes = (
  <Route ponent={App} path='/'>
    <Route ponent={Home} path='/test' />
  </Route>
);

const Routes = () => {
  return <Router history={ browserHistory } routes={ ponentRoutes } />
};

export default Routes;

The App ponent renders a single div saying it loaded and same for the Home ponent. If you care to see the entire thing on Github, here is a link:

https://github./jlag34/nodeWebpackSupport

The main goal is to be able to load '/test' in dev mode without using hashHistory.

Wepback docs: https://webpack.js/guides/development/

Share Improve this question asked Nov 13, 2017 at 7:25 user2465134user2465134 9,8635 gold badges34 silver badges51 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 8

You are serving dist/index.html when no other route was matched, with:

app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});

But this looks for that file on your file system, which should work in your production build (when you build the bundle and then serve it). If you look at the error you get when going to /test you will see that this file doesn't exist.

Error: ENOENT: no such file or directory, stat '/path/to/nodeWebpackSupport/dist/index.html'

This happens, because you're generating the index.html with html-webpack-plugin and webpack-dev-middleware keeps that in memory and doesn't write it to the file system. In development you cannot serve that file, but instead you need to serve the one from memory. You can access the files in webpack's memory with piler.outputFileSystem.readFile.

In your development routes you need to add the following (originally taken from the ment of html-webpack-plugin #145):

app.use('*', (req, res, next) => {
  const filename = path.resolve(piler.outputPath, 'index.html');
  piler.outputFileSystem.readFile(filename, (err, result) => {
    if (err) {
      return next(err);
    }
    res.set('content-type','text/html');
    res.send(result);
    res.end();
  });
});

The main goal is to be able to load '/test' in dev mode without using hashHistory.

React-router type as static, browser, hash and so one can be easily selected by generative jsx-function, which is selected by control flow or webpack predefined constants. Such technique is used for SSR (server-side rendering), when jsx with applied routes is returned, dependent on environment.

const RootComponent = () => {/* root ponent */};
const EntryPoint = process.env.NODE_ENV === 'production'
    ? (props) => (<BrowserRouter><RootComponent {...props} /></BrowserRouter>)
    : (props) => (<HashRouter><RootComponent {...props} /></HashRouter>)
export default EntryPoint 

本文标签: