在React.js,node.js,webpack,babel,express中使用fs模块 [英] Use fs module in React.js,node.js, webpack, babel,express

查看:116
本文介绍了在React.js,node.js,webpack,babel,express中使用fs模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个要求,我正在渲染我在其中显示表单的视图。在提交表单时,我需要收集表单数据并创建一个文件,并将表单数据保存为该文件中的JSON。我正在使用React.js,node.js,babel和webpack。

I have a requirement in which I am rendering view in which I display a form. On submit of form i need to gather the form data and create a file and save form data as JSON in that file. I am using React.js, node.js, babel and webpack.

经过努力实现这一点后我发现我必须使用同构或通用的javascript即因为我们不能在客户端使用fs模块,所以在服务器端使用react和render。
将此推荐给服务器端

After struggling a bit to achieve this I figured out that I have to use isomorphic or universal javascript i.e use react and render on server side as we cannot use fs module on client side. Referred this for server side.

我使用以下方式运行: npm run start

i run it using: npm run start

在此之后,我可以在控制台中看到 [Object Object] 从下面的第1行的控制台上打印出反应组件(HomePage) .js文件)。但是稍后我访问此页面时会出错:

After this I can see in console that [Object Object] is printed on console from Line 1 in below react component (HomePage.js). But later on when I access this page it gives an error:


'bundle.js:18未捕获错误:找不到模块fs '

'bundle.js:18 Uncaught Error: Cannot find module "fs"'

如何使用fs模块做出反应?

以下是代码段:

webpack.config.js

"use strict";

const debug = process.env.NODE_ENV !== "production";

const webpack = require('webpack');
const path = require('path');

module.exports = {
  devtool: debug ? 'inline-sourcemap' : null,
  entry: path.join(__dirname, 'src', 'app-client.js'),
  devServer: {
    inline: true,
    port: 3333,
    contentBase: "src/static/",
    historyApiFallback: true
  },
  output: {
    path: path.join(__dirname, 'src', 'static', 'js'),
    publicPath: "/js/",
    filename: 'bundle.js'
  },
  module: {
    loaders: [{
      test: path.join(__dirname, 'src'),
      loader: ['babel-loader'],
      query: {
        //cacheDirectory: 'babel_cache',
        presets: debug ? ['react', 'es2015', 'react-hmre'] : ['react', 'es2015']
      }
    }]
  },
  plugins: debug ? [] : [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: { warnings: false },
      mangle: true,
      sourcemap: false,
      beautify: false,
      dead_code: true
    }),
  ]
};

package.json

{
  "name": "sample",
  "version": "1.0.0",
  "description": "Simple application to showcase how to achieve universal rendering and routing with React and Express.",
  "main": "src/server.js",
  "scripts": {
    "start": "SET NODE_ENV=production&&babel-node src/server.js",
    "start-dev": "npm run start-dev-hmr",
    "start-dev-single-page": "node_modules/.bin/http-server src/static",
    "start-dev-hmr": "webpack-dev-server --progress --inline --hot",
    "build": "SET NODE_ENV=production&&webpack -p"
  },
  "dependencies": {
    "babel-cli": "^6.11.4",
    "babel-core": "^6.13.2",
    "babel-loader": "^6.2.5",
    "babel-plugin-react-html-attrs": "^2.0.0",
    "babel-preset-es2015": "^6.13.2",
    "babel-preset-react": "^6.11.1",
    "babel-preset-react-hmre": "^1.1.1",
    "ejs": "^2.5.1",
    "express": "^4.14.0",
    "react": "^15.3.1",
    "react-dom": "^15.3.1",
    "react-router": "^2.6.1"
  },
  "devDependencies": {
    "http-server": "^0.9.0",
    "react-hot-loader": "^1.3.0",
    "webpack": "^1.13.2",
    "webpack-dev-server": "^1.14.1"
  }
}

server.js

use strict';

import path from 'path';
import { Server } from 'http';
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import routes from './routes';
import NotFoundPage from './components/NotFoundPage';
//import fs from 'fs';

//console.log("server" + fs);
// initialize the server and configure support for ejs templates
const app = new Express();
const server = new Server(app);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

// define the folder that will be used for static assets
app.use(Express.static(path.join(__dirname, 'static')));

// universal routing and rendering
app.get('*', (req, res) => {
  match(
    { routes, location: req.url },
    (err, redirectLocation, renderProps) => {
//console.log("renderProps "+ Object.values(routes));
//console.log("req.url "+ req.url);
      // in case of error display the error message
      if (err) {
        return res.status(500).send(err.message);
      }

      // in case of redirect propagate the redirect to the browser
      if (redirectLocation) {
        return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
      }

      // generate the React markup for the current route
      let markup;
      if (renderProps) {
        // if the current route matched we have renderProps
        markup = renderToString(<RouterContext {...renderProps}/>);
      } else {
        // otherwise we can render a 404 page
        markup = renderToString(<NotFoundPage/>);
        res.status(404);
      }

      // render the index template with the embedded React markup
      return res.render('index', { markup });
    }
  );
});

// start the server
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
console.log(`Server starting on http://localhost:${port} [${env}]`)
server.listen(port, err => {
  if (err) {
    return console.error(err);
  }
  console.info(`Server running on http://localhost:${port} [${env}]`);
});

HomePage.js(React component)

HomePage.js (React component)

import React from 'react';
import fs from 'fs';  
import dateformat from 'dateformat';
console.log("home page" + fs);  -- Line 1
class HomePage extends React.Component{
 checkDirectory(directory, callback) {
    fs.stat(directory, function(err, stats) {
      //Check if error defined and the error code is "not exists"
      if (err && err.errno === 34) {
        //Create the directory, call the callback.
        fs.mkdir(directory, callback);
      } else {
        //just in case there was a different error:
        callback(err)
      }
    });
  }
 handleClick(){


    var obj = JSON.stringify($('#statusForm').serializeArray());
    
    this.checkDirectory("directory/"+currentDate, function(error) {
      if(error) {
        console.log("oh no!!!", error);
      } else {
        //Carry on, all good, directory exists / created.
        fs.writeFile("directory/"+currentDate+name+".json", obj, function(err) {
        if(err) {
            return console.log(err);
        }

        console.log("The file was saved!");
        });
        console.log("exists");
      }
    });*/

  }
  render() {
    return (
      <div className="container">

    <form id="statusForm" className="form-horizontal" >
      <div className="form-group">
        <label className="control-label col-sm-2" for="names">Select list:</label>
        <div className="col-sm-10">
          <select name="names" className="form-control" id="names">
            <option>Select</option>
            <option>abc</option>
            <option>xyz</option>
          </select>
        </div>
      </div>
      <div className="form-group">
        <label className="control-label col-sm-2" for="team">Select list:</label>
        <div className="col-sm-10">
          <select name="team" className="form-control" id="team">
            <option>Select</option>
            <option>team 1</option>
            <option>team 2</option>
          </select>
        </div>
      </div>
      <div className="form-group">
        <label className="control-label col-sm-2" for="pwd">Password:</label>
        <div className="col-sm-10">
          <input type="textarea" className="form-control" id="todayTask" name="todayTask" placeholder="Enter Task"/>
        </div>
      </div>
      <div className="form-group">
        <div className="col-sm-offset-2 col-sm-10">
          <button type="button" className="btn btn-default" onClick={this.handleClick.bind(this)}>Submit</button>
        </div>
      </div>
    </form>
  </div>
    );
  }
}


export default HomePage;

编辑1:

我调查了更多,发现如果我没有使用npm run build显式构建我的应用程序并且只是更新我的反应组件,我就不会出现上述错误。
此外,在此之后,如果我将文件创建逻辑直接放在render方法和刷新页面中,它就会成功创建一个文件。
因此观察它不适用于按钮的Onclick,并且如果我们刷新页面就可以工作。它转到服务器,这就是为什么它以这种方式工作。

I investigated more and found out that if i do not build my app explicitly using npm run build and just update my react component i do not get above error. Also, after this if i put file creation logic directly inside render method and on refreshing page it successfully create a file. So observation is it does not work with Onclick of button and can work if we refresh the page. it goes to server and thats why it works this way.

编辑2:

在我的webpack配置中使用target:'node'解决了页面刷新问题,但我收到错误:

Page refresh issue resolved by using target:'node' in my webpack config but I do get the error:


未捕获的ReferenceError:require未定义

Uncaught ReferenceError: require is not defined

在browser.so文件创建逻辑中,直接在render方法内部将在我们访问页面时创建文件。无需刷新。

In browser.so file creation logic directly inside render method will create the file the moment we access the page. No refresh required.

任何人都可以指导我达到所需要求的最佳方式是什么?

推荐答案

错误



首先让我们稍微讨论一下你的错误:

Errors

First let's go through your errors a little bit:

当你不使用 npm run build npm run start 时,你赢了'使用webpack,因此 require 语句不会被 fs 模块的内容替换 - 而是你留下一个require语句,浏览器无法理解,因为require是一个仅限节点的函数。因此,您的错误有关未定义的要求。

When you don't use npm run build or npm run start, you won't use webpack and therefore the require statement doesn't get replaced with the contents of the fs module--instead you are left with a require statement, which your browser doesn't understand since require is a Node-only function. Thus, your error about require not being defined.

如果您使用运行npm run build npm run start ,webpack将该require语句取出并用 fs 模块替换它。但是,正如您所发现的那样, fs 在客户端无效。

If you do run with npm run build or npm run start, webpack takes that require statement out and replaces it with the fs module. But, as you've discovered, fs doesn't work on the client side.

因此,如果您不能使用 fs 来保存文件,您可以做什么?

So, if you can't use fs to save files, what can you do?

如果您尝试将文件保存到服务器,则必须将表单中的数据提交到节点服务器,节点服务器可以使用 fs 与服务器的文件系统进行交互以保存文件。

If you are trying to save the file to a server, you have to submit data from your form to the Node server, and the Node server can use fs to interact with the server's filesystem to save the file.

如果您尝试在本地保存表单,即在与浏览器相同的设备上保存表单需要使用其他策略,如或使用客户端库,如 FileSaver 。您选择哪个选项在某种程度上取决于您的使用案例,但如果您尝试在客户端保存,则可以搜索从Web浏览器保存文件或保存文件客户端以查看哪些适合您。

If you are trying to save the form locally, i.e., on the same device as the browser, you need to use another strategy like this or by using a client-side library like FileSaver. Which option you take depends somewhat on your use case, but if you are trying to save on the client side you can search around "saving files from web browser" or "saving files client side" to see what works for you.

这篇关于在React.js,node.js,webpack,babel,express中使用fs模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆