简体   繁体   English

在React.js,node.js,webpack,babel,express中使用fs模块

[英]Use fs module in React.js,node.js, webpack, babel,express

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. 在提交表单时,我需要收集表单数据并创建一个文件,并将表单数据保存为该文件中的JSON。 I am using React.js, node.js, babel and webpack. 我正在使用React.js,node.js,babel和webpack。

After struggling a bit to achieve this I figured out that I have to use isomorphic or universal javascript ie use react and render on server side as we cannot use fs module on client side. 经过努力实现这一点后,我发现我必须使用同构或通用的javascript,即在服务器端使用react和render,因为我们不能在客户端使用fs模块。 Referred this for server side . 将此提交给服务器端

i run it using: npm run start 我运行它: npm run start

After this I can see in console that [Object Object] is printed on console from Line 1 in below react component (HomePage.js). 在此之后,我可以在控制台中看到[Object Object]在下面的反应组件(HomePage.js)中从第1行打印到控制台上。 But later on when I access this page it gives an error: 但是稍后当我访问此页面时,它会出错:

'bundle.js:18 Uncaught Error: Cannot find module "fs"' 'bundle.js:18未捕获错误:找不到模块“fs”'

How can i use fs module with react ? 我怎样才能使用fs模块做出反应?

Below are code snippets : 以下是代码段:

webpack.config.js 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 的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 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组件)

 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; 

EDIT 1: 编辑1:

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. 我调查了更多,发现如果我没有使用npm run build显式构建我的应用程序,只是更新我的反应组件,我不会得到上述错误。 Also, after this if i put file creation logic directly inside render method and on refreshing page it successfully create a file. 此外,在此之后如果我将文件创建逻辑直接放在render方法中并且在刷新页面上它成功创建了一个文件。 So observation is it does not work with Onclick of button and can work if we refresh the page. 所以观察它不适用于按钮的Onclick,如果我们刷新页面就可以工作。 it goes to server and thats why it works this way. 它去了服务器,这就是为什么它以这种方式工作。

EDIT 2: 编辑2:

Page refresh issue resolved by using target:'node' in my webpack config but I do get the error: 在我的webpack配置中使用target:'node'解决了页面刷新问题,但我收到错误:

Uncaught ReferenceError: require is not defined 未捕获的ReferenceError:未定义require

In browser.so file creation logic directly inside render method will create the file the moment we access the page. 在browser.so中,文件创建逻辑直接在render方法内部将在我们访问页面时创建文件。 No refresh required. 无需刷新。

Can anyone guide me what is the best way to achieve my desired requirement? 任何人都可以指导我达到我想要的要求的最佳方法是什么?

Errors 错误

First let's go through your errors a little bit: 首先让我们稍微讨论一下你的错误:

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. 当你不使用npm run buildnpm run start ,你不会使用webpack,因此require语句不会被fs模块的内容替换 - 而是留下一个require语句,你的浏览器无法理解,因为require是仅限节点的功能。 Thus, your error about require not being defined. 因此,您的错误无需定义。

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. 如果您使用npm run buildnpm run start ,webpack会将该require语句取出并将其替换为fs模块。 But, as you've discovered, fs doesn't work on the client side. 但是,正如您所发现的, fs在客户端不起作用。

Alternatives 备择方案

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. 如果您尝试将文件保存到服务器,则必须将表单中的数据提交到节点服务器,并且节点服务器可以使用fs与服务器的文件系统进行交互以保存文件。

If you are trying to save the form locally, ie, on the same device as the browser, you need to use another strategy like this or by using a client-side library like FileSaver . 如果您尝试在本地保存表单,即与浏览器在同一设备上,则需要使用此类策略或使用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. 您选择哪个选项取决于您的使用案例,但如果您尝试在客户端保存,则可以搜索“从Web浏览器保存文件”或“保存文件客户端”以查看哪些对您有用。

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

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