简体   繁体   English

节点,Webpack-Dev-Server,React的开发模式-嵌套路由没有此类文件或目录

[英]Dev Mode for Node, Webpack-Dev-Server, React - No Such File or Directory for Nested Routes

I am trying to get my application to work in development mode with Node and Webpack-Dev-Server. 我试图让我的应用程序在Node和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'. 但是,当我执行'/ test'时,我得到的是'没有这样的文件或目录'。 I have read a lot of documentation on Webpack's website and React Router Training, none seem to really answer this issue. 我已经在Webpack的网站和React Router Training上阅读了很多文档,似乎都没有真正回答这个问题。 I want to be able to use browserHistory instead of hashHistory (I am still using React-Router v3). 我希望能够使用browserHistory而不是hashHistory(我仍在使用React-Router v3)。

package.json: 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 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: 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 compiler = webpack(config);
  app.use(webpackDevMiddleware(compiler, {
    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: route.js:

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

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

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

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

export default Routes;

The App component renders a single div saying it loaded and same for the Home component. App组件呈现一个单独的div,表示它已加载,并且与Home组件相同。 If you care to see the entire thing on Github, here is a link: 如果您想在Github上查看全部内容,请访问以下链接:

https://github.com/jlag34/nodeWebpackSupport https://github.com/jlag34/nodeWebpackSupport

The main goal is to be able to load '/test' in dev mode without using hashHistory. 主要目标是能够在开发模式下加载'/ test'而不使用hashHistory。

Wepback docs: https://webpack.js.org/guides/development/ Wepback文档: https ://webpack.js.org/guides/development/

You are serving dist/index.html when no other route was matched, with: 没有其他路由匹配时,您正在提供dist/index.html ,其中包括:

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. 如果查看在/test时遇到的错误,您将看到此文件不存在。

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. 发生这种情况是因为您正在使用html-webpack-pluginwebpack-dev-middleware生成index.html并将webpack-dev-middleware保存在内存中,并且不会将其写入文件系统。 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 compiler.outputFileSystem.readFile . 您可以访问的WebPack与内存中的文件compiler.outputFileSystem.readFile

In your development routes you need to add the following (originally taken from the comment of html-webpack-plugin #145 ): 在开发路线中,您需要添加以下内容(最初取自html-webpack-plugin #145注释 ):

app.use('*', (req, res, next) => {
  const filename = path.resolve(compiler.outputPath, 'index.html');
  compiler.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. 主要目标是能够在开发模式下加载'/ test'而不使用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. 可以通过生成jsx函数轻松选择React-router类型,如staticbrowserhash等,可以通过控制流或webpack预定义常量进行选择。 Such technique is used for SSR (server-side rendering), when jsx with applied routes is returned, dependent on environment. jsx带有应用路由的jsx时(取决于环境),该技术用于SSR(服务器端呈现)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM