Webpack连忙营造react程序,记录跨域问题的消除方式

By admin in 4858美高梅 on 2019年4月1日

react
跨域访问后台,暗中同意是有跨域难题,并且火弧和谷歌(Google)浏览器,对跨域难点显得还不同.

背景:项目初期平昔在create-react-app脚手架配置好的条件下写静态页面,用react-router-dom
v4.x看成路由模块,开启的是客户端服务器。
不久前尝试将express脚手架生成的施用作为后台服务器,与react应用实行数量交互。

webpack等包裹工具出现的由来

乘胜前端技术的发展壮大,前端慢慢能处理越来越复杂的逻辑与运算,代码量也日趋增多,为了支付结构的清晰,模块化出现了,将富有较强涉嫌的代码组合到独门的文件中,方便编写和护卫。
随之而来的难点就是对传输的影响,是文本每种按需传输,依然完全包装二遍性传输,恐怕有更好的其它化解方案?前两者均有利弊,不能够太如意,智能包裹工具便出现。webpack的兵不血刃在于,不仅其自小编能够解析js,而其loader效率能够将其余的静态财富转换为js。

本文重要介绍的是使用React-router和Webpack如何急速营造二个react程序,上面话不多说,感兴趣的能够一并念书深造。

谷歌(谷歌)浏览器如下图:

  1. 先是在顶峰生成贰个express应用命名为react-backend,作为项指标根目录
    $ express react-backend
  2. 然后在./routes/user.js中期维修改代码为

条件布署

以react-webpack为例表明二者结合后的中央采取办法

  • 新建目录,起首化npm环境
    安装node;
    设置cnpm,可安装nrm,方便源的切换;
    开始化项目npm重视配置,npm init -y,以私下认可选项生成
    package.json

npm安装中–save-dev和–save选项的分别?
–save-dev,包参预package.json的dependencies中,作为开发时索要的重视
–save,包参与devDpendenies中,作为发表时需求的依靠

  • 安装webpack相关依赖
    安装webpack
    sudo cnpm i webpack webpack-dev-server —save-dev

  • 配置webpack-dev-server
    在package.json中的scripts字段添加如下项:
    "dev": "webpack-dev-server --devtool eval --colors --progress"
    透过浏览器http://localhost:8080可访问到页面

  • webpack插件选装
    设置open-browser-webpack-plugin,使webpack运营时自动打开浏览器新标签

npm i open-browser-webpack-plugin --save-dev
// webpack.config.js中添加配置
var OpenBrowserPlugin = require('open-browser-webpack-plugin')
plugins: [
  new OpenBrowserPlugin({
    url: 'http://localhost:8080'
   })
]

设置html-webpack-plugin,扶助自动生成index.html

npm i html-webpack-plugin --save-dev`
var HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
  new HtmlWebpackPlugin()
]

webpack-dev-server热替换

//添加插件
plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
//增加入口
entry: [
    'webpack/hot/dev-server',
    'webpack-dev-server/client?http://localhost:8080',
    './index.js'
  ],
/*
在webpack.config.js中设置publicPath为/assets/
将index.html中的入口脚本src设为'/assets/bundle.js'
启动webpack-dev-server
*/
  • jsx语法 ,babel-core
    设置重视包
    Webpack连忙营造react程序,记录跨域问题的消除方式。npm i babel-loader babel-core babel-preset-es2015 babel-preset-react
    –save-dev
    新建.babelrc文件,并配置

//配置.babelrc
{
  ‘presets’: [
    ‘es2015’, //es2015转码
    ‘react’//react转码
  ]
}
  • 安装react
    npm i react react-dom —save-dev

  • 安装eslint
    npm i babel-eslint –save-dev
    配置eslint airbnb config

npm i eslint eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react eslint-config-airbnb --save-dev
// 编辑webpack.config.js
preLoaders: [
  {
    test: /\.jsx?$/,
    loaders: ['eslint-loader'],
    include: path.join(__dirname, 'src'),
    exclude: path.join(__dirname, 'src/app/container')
  }
],
eslint: {
  configFile: './.eslintrc',
  emitWarning: true
}
// 新建.eslintrc
{
  "extends": "airbnb"
}
  • 蒙受的标题
  1. 利用webpack –display-error-details选项开启报错音信详情
  2. react的jsx安装并配置了babel-loaer的事态下,依旧报错,Module build
    failed: SyntaxError:找不到模块
    import App from ‘App.js’
    改为
    import App from ‘./App.js’
    因为import暗许路径是node_modules中,而”.”代表的近年来路线是进口脚本所在路径

起始化项目

4858美高梅 1

我们先创设个空文件夹,然后初步化 package.json ,填写部分骨干音信。

那边状态是200,可是在Response却并未其他音信,如下图

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
    res.json([
    {id:1,username:"wyy"},
    {id:2,username:"wyp"}
  ]);
});

module.exports = router;
$ npm init

4858美高梅 2

  1. 在react-backend文件夹下运维express,并且钦点端口为3001,制止与react的暗中同意端口三千发生抵触。
    ~/wyy/react-backend% PORT=3001 node bin/www
    开辟localhost:3001收看如下画面,表示后台服务器应用已经在3001端口运转。

    4858美高梅 3

    image.png

接下去大家开头设置依赖项,笔者的 package.json 的借助项如下

 

开拓localhost:3001/users观看如下画面,正是大家刚刚写在routes/users.js里面包车型地铁json数据。

 "devDependencies": {
 "babel": "^5.5.6",
 "babel-core": "^5.5.6",
 "babel-loader": "^5.1.4",
 "history": "^1.13.1",
 "react": "^0.13.3",
 "react-hot-loader": "^1.2.7",
 "react-router": "^0.13.3",
 "webpack": "^1.12.6",
 "webpack-dev-server": "^1.12.1"
 } 

只是火弧浏览器,对该问题的描述,就清淅得多,

4858美高梅 4

运作命令:

4858美高梅 5

image.png

$ npm install 

火弧浏览器告诉大家,跨域了,关于react跨域的帖子,网上也有有关帖子,搜索到的主意,大致都是之类消除措施:

  1. 近日打开二个新的顶峰窗口,在品种根目录下生成新的react应用
    $create-react-app client
  2. 修改client文件夹下的package.js文件如下。添加proxy,钦点代理服务器为3001端口运维的行使。

类型成立好后,大家接下去创设一些必不可少的文书和目录;

假定你是经过creat-react-app构建的门类,请在package.json文件中的根目录下,添加”proxy”:

$ mkdir js css && touch index.html webpack.config.js
"proxy": {
        "/api/RoomApi": {
          "target": "http://open.douyucdn.cn",
          "changeOrigin":true
        },
        "/api/v1":{
          "target":"http://capi.douyucdn.cn",
          "changeOrigin":true
        }
      }
{
  "name": "antd-demo",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "antd": "^3.2.3",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-router-dom": "^4.2.2",
    "react-scripts": "1.1.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom"
  },
  "proxy": "http://localhost:3001"
}

webpack

对于antd-pro的档次,须求在package.json的一致目录下添加.roadhogrc文件,具体代码如下:

  1. 在client文件夹下,运维react应用。
    ~/wyy/react-backend/client% npm start
    那儿开拓localhost:两千,看到react应用的画面
    柒 、在react组件中,能够透过在compenentDidMount(){}方法中写入fetch交互数据的代码,类似于ajax的$.get()

webpack
是一款模块处理器,他会将你拥有的代码打包成静态文件,放到你的开发的App中。

    {
      "entry": "src/index.js",
      "extraBabelPlugins": [
        "transform-runtime",
        "transform-decorators-legacy",
        "transform-class-properties",
        ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": true }]
      ],
      "env": {
        "development": {
          "extraBabelPlugins": [
            "dva-hmr"
          ]
        }
      },
      "externals": {
        "g2": "G2",
        "g-cloud": "Cloud",
        "g2-plugin-slider": "G2.Plugin.slider"
      },
      "ignoreMomentLocale": true,
      "theme": "./src/theme.js",
      "proxy": {
        "/api": {
          "target": "http://api.xxxx.com/",
          "changeOrigin": true
        }
      }
    }

开辟webpack.config.js,然后添加上面包车型地铁代码:

配备达成后,再度走访接口,依然出现相同的跨域难点,既然recat的布署,未缓解跨域难点,小编就把思路转到spring,在spring去处理跨域,在后端程序添加二个拦截器,

componentDidMount() {
  fetch('path').then()
}
var webpack = require('webpack'); 
module.exports = { 
 entry: [
  'webpack/hot/only-dev-server',
  "./js/app.js"
 ],
 output: {
  path: __dirname + '/build',
  filename: "bundle.js"
 },
 module: {
  loaders: [
   { test: /\.js?$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/ },
   { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
   { test: /\.css$/, loader: "style!css" }
  ]
 },
 plugins: [
  new webpack.NoErrorsPlugin()
 ]
};
package com.gg.interceptor;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class ProcessInterceptor implements HandlerInterceptor{

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler)
            throws Exception {
        // TODO Auto-generated method stub 
        // 指定白名单域名   http://localhost:8000,http://localhost:8000
        List<String> whileList  = new Vector<String>(); 
        whileList.add("http://127.0.0.1:8000");
        whileList.add("http://localhost:8000");
        String clientIp = httpServletRequest.getHeader("origin");
        boolean status = false;
        for(String ip : whileList) {
            if(clientIp!=null&&clientIp.equals(ip)) {
                status = true;
                break;
            }
        }
        /**
         * 网上解决方案是httpServletResponse.setHeader("Access-Control-Allow-Origin","*");设置后发现,还是不能处理跨域问题,需要指定某一个ip,如:http://127.0.0.1:8000  
         * */
        httpServletResponse.setHeader("Access-Control-Allow-Origin",status?clientIp:null);  
        //响应头设置  
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");  
        //响应类型
        httpServletResponse.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  
        httpServletResponse.setHeader("X-Powered-By","Jetty");  
        httpServletResponse.setHeader("Access-Control-Allow-Credentials","true");
        String method= httpServletRequest.getMethod();  
        if (method.equals("OPTIONS")){  
            httpServletResponse.setStatus(200);  
            return false;  
        }  

        System.out.println(method+",status:"+status+",clientIp:"+clientIp);  

        return true;  
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub

    }

}

参考地址
https://daveceddia.com/create-react-app-express-backend/
https://esausilva.com/2017/11/14/how-to-use-create-react-app-with-a-node-express-backend-api/
https://www.cnblogs.com/LLLLily/p/7492118.html

那份文件大致有多少个布局项entry, output, module,plugins.

spring-servlet.xml配置如下:


      entry:内定打包的输入文件,每有3个键值对,便是多个进口文件。

<mvc:interceptors>  
       <bean class="com.gg.interceptor.ProcessInterceptor"></bean>  
   </mvc:interceptors>  

20180320更新 更简单的布局格局

用express脚手架搭建的express太繁琐,下边是更简明的情势。

  1. 将create-react-app生成的整整文件夹直接放在项目根目录下的client文件夹中,然后在根目录下展开yarn
    init,package.json文件如下

{
  "name": "antd-demo",
  "version": "1.0.0",
  "scripts": {
    "client": "cd client && yarn start",
    "server": "nodemon server.js",
    "start": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\""
  },
  "dependencies": {
    "express": "^4.16.2"
  },
  "devDependencies": {
    "concurrently": "^3.5.0"
  }
}
  1. 下一场在极限执行yarn安装重视包,concurrenly是三个方可通过布署命令来还要运营两个服务器的插件。通过在package.json中的scripts下修改命令,能够而且拉开服务端和客户端。
  2. 在项目根目录下新建server.js,内容如下

const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
app.get('/api/hello', (req, res) => {
    res.send({
        express: 'Hello From Express'
    });
});
app.listen(port, () => console.log(`Listening on port ${port}`));
  1. 4858美高梅 ,在client文件夹下的package.json中布局代理同上,端口和服务器端端口设为直接
  2. 在巅峰进入项目根目录,执行yarn start即可同时开班客户端和劳务器端。

     
output:配置打包结果,path定义了出口的文件夹,filename则定义了打包结果文件的名目,filename里面包车型客车[name]会由entry中的键替换,例子中的/build/bundle.js就是变化的文件。

react客户端代码如下:

20180322改进 补充部分代码才能一心缓解跨域请求数据的配备难点

  1. 先对前边的步骤实行计算:
    (1)在不一致的端口开启客户端服务器和后台服务器
    (2)在react的package.json中添加proxy
  2. 然后介绍前几天在此之前端表单发送数据到后台服务器的时候,跨域请求报错
    (1)在server.js中添加代码

app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

(2)在前者login组件中通过fetch方法发送数据的时候,添加3个允许跨域的属性
mode:“no-cors”

fetch('http://localhost:5000/post/api/1.0/create',
            {
                method:"POST",
                mode:"no-cors",//跨域
                body:JSON.stringify({
                  phone:values.phone,
                  password:values.password,
                }),
                headers:{
               "Content-type":"application/json;charset=utf-8"
                }
            })
            .then(function(values){
              console.log('注册成功',values)
            })
            .catch(function(error){
              console.log('注册失败',error)
            })
      }

     
resolve:定义了剖析模块路径时的安顿,常用的正是extensions,能够用来钦命模块的后缀,那样在引入模块时就不必要写后缀了,会活动补全.

Model层js代码:
*login({ payload }, { call, put }){
      let formData = new FormData();
      formData.append("loginId",payload.loginId);//账号
      formData.append("passWord",payload.passWord);//密码
      const response = yield call(requestGuangGao, formData); 
      yield put({
        type: 'changeLoginStatus',
        payload: response,
      });
    },

api层js代码:
export async function requestGuangGao(formData){
  // let formData = new FormData();
  // formData.append("loginId",params.loginId);
  // formData.append("passWord",params.passWord);

  console.log("requestGua   >url  :" );
   return request('http://127.0.0.1:8080/guanggao/userController/login.do', {
    method: 'POST', 
    mode: 'cors', 
    body:formData,
  });   
}

     
module:定义了对模块的处理逻辑,那里能够用loaders定义了一多级的加载器,以及一些正则。当需求加载的公文匹配test的正则时,就会举办拍卖。那里我们采纳了react-hot
和 babel。babel-loader是大家选用ES-6实行支付时用于生成JS文件。
最终大家转变了二个style.css仅仅做个例证,告诉我们怎么引入样式文件,实际上大家可以加载诸如sass-loader那样的加载器。

通过以下设置,react跨域难题就处理好了。

     
loader对文本实行处理,那正是webpack强大的原故。比如那里定义了凡是.js结尾的文本都是用babel-loader做处理,而.jsx结尾的公文少禽先通过jsx-loader处理,然后通过babel-loader处理。当然这么些loader也必要经过npm
install安装。

      plugins:
那里定义了索要利用的插件,比如commonsPlugin在包装两个输入文件时会提取出公用的局地,生成common.js。

      NoErrorsPlugin: 定义代码出现谬误时的时受否自动重新加载。

那一个时候大家再package.json中参预script 字段,

"scripts": {
 "start": "webpack-dev-server --hot --progress --colors",
 "build": "webpack --progress --colors"
 }

以此时候大家输入三个npm start命令时候我们会运维贰个webpack
server这些时候你能够访问localhost:8080/webpack-dev-server/#/;假使您利用npm run build时候能够将文件自动生成到bulid/下。

接下去大家新建index.html文件

<!doctype html> 
<html lang="en"> 
 <head>
 <meta charset="utf-8">
 <title>New React App</title>
 </head>
 <body>
 <section id="react"></section>
 <script src="bundle.js"></script>
 </body>
</html> 

近年来我们走访浏览器可以便会推荐新创立的bundle.js,实际上你能够推荐其余你想要的财富。

React-router

完毕项目标主旨创立,接下去大家创设app.js项目的进口文件。

代码如下:

import React from 'react'; 
import Router from 'react-router'; 
import { DefaultRoute, Link, Route, RouteHandler } from 'react-router';

import LoginHandler from './components/Login.js';

let App = React.createClass({ 
 render() {
 return (
  <div className="nav">
  <Link to="app">Home</Link>
  <Link to="login">Login</Link>

  {/* this is the importTant part */}
  <RouteHandler/>
  </div>
 );
 }
});

let routes = ( 
 <Route name="app" path="/" handler={App}>
 <Route name="login" path="/login" handler={LoginHandler}/>
 </Route>
);

Router.run(routes, function (Handler) { 
 React.render(<Handler/>, document.body);
});

文章底部是我们将要用的react和react-router的插件包引进来。同事大家还引入login.js作为大家的Login
React 组件。接着,我们应用React
创设三个类。那么些事例中,其实正是一个归纳的领航条会出现全部的子组件中。我们大概的Link到大家的路由:App和Login.然后React
route将会被RouteHandler组件初始化。

在那么些App中,大家定义路由并且钦赐了相应的处理程序(React
组件)。大家定义了作者们的根路径为app,并且别的的地点将会是App的子组件。这么些例子中,我们添加了1个记名页面,用于用户登录到App中。

说到底,React-router会将大家定义的全部加载到document.body中来。那正是index.html转变成大家React
App.

Components

弄到这了,我们须求添加组件(Components).在我们的 /js
目录下,大家必要开头创办组件。

我们创立Login.js:

import React from 'react';

let Login = React.createClass({ 

 render() {
 return(<div>Welcome to login</div>);
 }
});

export default Login; 

实则那只是一个相当简单的零件,内容为显示”Welcaome to
Login”。这一个时候我们得以运作下大家的app。npm start下一场访问http://localhost:8080/webpack-dev-server/#

本条时候,你能够看到贰个导航条上有八个链接Home 和
Login.要是点击Login那个时候能够显得大家正好创立的始末。

万一地点一切顺利,那么今后你能够团结创办越多内容来充实本人App.假若你项目中使用Flux,你能够在你的js
文件夹下使用其它组织。

发布

实质上大家有不少主意能够上线你的劳动,不过十一分好的一件工作是webpack
能够轻松的使用生成的文件。个中你可以快捷的将那几个财富文件放到cdn上,然后将index.html放到主机上,更新大家的本子路径就足以了。

总结

上述正是那篇文章的全体内容了,希望本文的内容对大家的学习也许办事能带来一定的支援,如若有问号我们能够留言交流。多谢大家对台本之家的支撑。

你只怕感兴趣的文章:

  • webpack3+React 的布置全解
  • react.js使用webpack搭配环境的入门教程
  • 浅谈react+es6+webpack的底子配置
  • webpack
    2.x安顿reactjs基本支出环境详解
  • webpack
    2的react开发配置实例代码
  • 详解基于webpack搭建react运维环境
  • webpack入门+react环境安排
  • React + webpack
    环境计划的法门步骤

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有