webpack 配置react脚手架
1 react 基本js文件:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx'; ReactDOM.render(<App/>,document.getElementById('root')) // 把app组件传给 reactCreateElement 作为的参数 要引入 react
基本 webpack.config 配置:
const path = require('path');
module.exports = {
entry:[
app: path.join(__dirname,'../clinet/app.js'); //使用path,设置绝对路径,注意 dirname前面是两个下划线
],
output:[
filename:'[name].[hash].js', //依赖的文件发生变化的时候,hash值变化。
path:path.join(__dirname,'../dist'),//输出的绝对路径
publicPath:'/public' //设置引用文件的公共路径,用于设置CDN的路径
],
module:{
rules:[
{
test:/.jsx$/,
loader:'babel-loader'//编译jsx,es6,es7等语法
//这里要安装 babel: npm i babel-loader -D
//babel-loader只是一个webpack的插件,不包括babel的核心代码,所以还要安装:
//babel-core: npm i bable-core -D
//此外,bable-core 默认是编译 es6的,为了还编译jsx,所以要进行另外的配置:.babelrc 文件
}
]
}
}
对应的 babelrc文件
// .babelrc 文件
{
"presets":[ //指定babel编译哪些类型
["es2015",{"loose":true}],//指定 es2015是 松散的不是严格的
"react" //在这里加上react,这个支持之后,babel才会编译react代码
]
}
//安装上述依赖文件:
// npm i babel-preset-es2015 babel-preset-es2015-loose babel-preset-react -D
为了打开html文件:
安装: 1 npm i html-webpack-plugin -D
webpack.config.js 文件
const path = require('path');
const HTMLPlugin =require('html-webpack-plugin')
module.exports = {
entry:[
app: path.join(__dirname,'../clinet/app.js'); //使用path,设置绝对路径,注意 dirname前面是两个下划线
],
output:[
filename:'[name].[hash].js', //依赖的文件发生变化的时候,hash值变化。
path:path.join(__dirname,'../dist'),//输出的绝对路径
publicPath:'/public/' //设置引用文件的公共路径,用于设置CDN的路径
],
module:{
rules:[
{
test:/.jsx$/,
loader:'babel-loader'//编译jsx,es6,es7等语法
//这里要安装 babel: npm i babel-loader -D
//babel-loader只是一个webpack的插件,不包括babel的核心代码,所以还要安装:
//babel-core: npm i bable-core -D
//此外,bable-core 默认是编译 es6的,为了还编译jsx,所以要进行另外的配置:.babelrc 文件
},
{
test:/.js$/,
loader:'babel-loader',
exclude:[
path.join(__dirname,'../node_modules')
]
}
]
},
plugins:[
new HTMLPlugin(); //有两个作用:1 生成html文件 ,2:根据output的配置把entry 文件打包
]
}
2 服务端渲染的配置
单页面存在的问题:
1 SEO不友好
2 首次请求等待时间过长,体验不友好。
首先看一下客户端的入口文件 app.js
客户端的入口文件 import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx'; ReactDOM.render(<App/>,document.getElementById('root'))
对比服务端渲染的入口文件 server-entry.js 文件:都是为了引入 最外层组件 <App/> 但是服务端没有dom元素,所以只能抛出 <App/> 组件,而不能挂载到 root的div节点上。
// 在服务端运行的文件
import React from 'react';
import App from './App.jsx'; export default <App/>
服务端和客户端的入口文件都是把<App> 组件提供出来,不同的是客户端可以直接把组件挂载到 root上。而服务器端的入口文件是提供 <App/>组件,之后在服务器端的server.js中,将其挂载到root中;且客户端和服务器端用的是同一个html模板。因为入口文件不同,所以两个的webpack配置文件也不同:
新建一个服务器端的webpack打包的文件:
const path = require('path');
module.exports = {
target:'node', //这里是新的配置,web/node 规定在哪里使用
entry:[
app: path.join(__dirname,'../clinet/serve-entry.js');
],
output:[
filename:'server-entry.js', //node.js 去 improt 这个js文件,且在服务器端没有缓存,不需要hash
path:path.join(__dirname,'../dist'),//输出的绝对路径
publicPath:'/public/',
libraryTarget: 'commonjs2' //打包出来的js 使用的模块方案, 包括 AMD CMD CommonJS等规范,这里使用的是commonjs2,适用于node端
],
module:{
rules:[
{
test:/.jsx$/,
loader:'babel-loader'//编译jsx,es6,es7等语法
//这里要安装 babel: npm i babel-loader -D
//babel-loader只是一个webpack的插件,不包括babel的核心代码,所以还要安装:
//babel-core: npm i bable-core -D
//此外,bable-core 默认是编译 es6的,为了还编译jsx,所以要进行另外的配置:.babelrc 文件
},
{
test:/.js$/,
loader:'babel-loader',
exclude:[
path.join(__dirname,'../node_modules')
]
}
]
}
}
修改配置项:
//修改 package.json文件 {
"script":{
"build:clinet": "webpack --config build/webpack.config.client.js",
"build:server": "webpack --config build/webpack.config.server.js",
"clear": "rimraf dist" //rimraf 是node的一个包,专门用来删除文件夹
"build": "npm run clear && npm run build:client && npm run build:server",
}
}
//安装rimraf包。 npm i rimraf -D
然后每次打包完,会有三个文件 客户端的js 服务器端的js 还有一个html。
上面介绍的是 客户端和服务器端的 webpack 配置文件;
===================
下面编写 express 服务端:
首先安装 npm i express -S
新建 server文件夹 建立 server.js文件:
说明: 1. dist/server-entry文件是打包生成的js文件;res.send()渲染的就是生成的js文件;
2. app.get 获取到浏览器所有的请求,返回 渲染的 js文件;监听端口在3333
3. 由于html中 使用的是es6的语法: export default <App/>;而node中又不能使用 impront { app } from './app' 这种结构赋值的语法,所以这里要用 require().default 获取默认值;
然后在配置json文件中,设置服务端启动命令:
{
"script":{
"start": "node server/server.js "
}
}
运行服务端代码之后,服务端返回的只是打包后入口文件中写的代码 字符串:‘<div></div>’,我们需要返回的是整个html。
步骤一:先在client文件夹下新建 模板文件 template.html: 其中关键代码:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root"><!--app--></div>
</body>
</html>
把生成的文件覆盖掉 <!--app-->;
然后修改客户端的配置文件。webpack.config.client.js中的模板插件:
{
plugins: [
new HTMLPlugin({
template: path.join(__dirname, '../client/template.html')
})
]
}
注意这里是改动的客户端的配置文件,客户端打包生成的html文件 ,然后服务端 server.js 去引用:
const express = require('express')
const ReactSSR = require('react-dom/server');
const fs = require('fs')
const path = require('path')
const serverEntry = require('../dist/server-entry').default;//引入的是服务端的配置打包后的js文件
const template = fs.readFileSync(path.join(__dirname, '../dist/index.html'), 'utf8')//同步引入客户端打包生成的 html 文件,如果不使用 utf8 则是buffer文件 const app = express();
app.use('/public', express.static(path.join(__dirname, '../dist'))); //给静态文件指定返回内容,这里给piblic文件夹下的内容返回的是静态文件的dist文件夹 app.get('*', function (req, res) {
const appString = ReactSSR.renderToString(serverEntry);
res.send(template.replace('<!--app-->',appString)) //用返回的js文件替换掉模板中的<app>,然后发送的是模板文件
}) app.listen(3333, function () {
console.log('server is listening on 3333')
})
注意的是: 客户端和服务端的 output配置中的 publicPath 要写为“public”
output:[
filename:'[name].[hash].js', //依赖的文件发生变化的时候,hash值变化。
path:path.join(__dirname,'../dist'),//输出的绝对路径
publicPath:'/public' //设置引用文件的公共路径,用于设置CDN的路径
]
这样生成的html中引用的静态文件js和css以及图片等路径前缀都是在public下,所以 上面的服务端 server.js 的
app.use('/public', express.static(path.join(__dirname, '../dist')));
给访问的 public 目录下的文件返回 dist文件夹下的文件,其他的 * 返回 模板文件
- 问题1 为啥还要在 服务端的配置文件中 设置 public
- 问题2 服务端的 server-entry.js 和 客户端的 app.js 有啥区别?
客户端的入口文件 app.js 可以对浏览器进行操作,比如
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx'; ReactDOM.render(<App/>,document.getElementById('root'))
而服务器端的入口文件 server-entry 不可以:
import React from 'react';
import App from './App.jsx'; exprot defalut <App/>
所以后续,对应的webpack.config配置文件也需要设置两个,分别对应客户端和服务器端;
他们两个的入口和出口配置不一样
客户端的配置文件:
{
entry:[
app: path.join(__dirname,'../clinet/app.js'); //使用path,设置绝对路径,注意 dirname前面是两个下划线
],
output:[
filename:'[name].[hash].js', //依赖的文件发生变化的时候,hash值变化。
path:path.join(__dirname,'../dist'),//输出的绝对路径
publicPath:'/public' //设置引用文件的公共路径,用于设置CDN的路径
],
}
服务器端的配置文件:
{
target:'node', //这里是新的配置,web/node 规定在哪里使用
entry:[
app: path.join(__dirname,'../clinet/serve-entry.js');
],
output:[
filename:'server-entry.js', //node.js 去 improt 这个js文件,且在服务器端没有缓存,不需要hash
path:path.join(__dirname,'../dist'),//输出的绝对路径
publicPath:'/public/',
libraryTarget: 'commonjs2' //打包出来的js 使用的模块方案, 包括 AMD CMD CommonJS等规范,这里使用的是commonjs2,适用于node端
],
}
因此,服务器端和客户端是单独的入口js文件和输出文件。
客户端: client/app.js------> dist/app.hash.js 文件,如下图所示,其提供的组件<App/>挂载到 root下;
服务器端: client/server-entry.js------> dist/server.entry.js 文件,在服务器端 server/server.js的作用下,将其生成的<App/>组件挂载到 root 下。
也就是说,客户端的app.js文件,生成的组件挂载到 root上;服务器端把server-entry生成的组件直接挂载到 root 上。
根据模板文件生成:
<body>
<div id="root"><!-- app --></div>
<script type="text/javascript" src="/public/app.9337b7bd3bfeb9af5f86.js"></script>
</body>
两个是独立的,所以两个都要加 /public,这样服务器就会根据两个位于 public 文件夹下 而返回对应的app.hash.js 和 server.entry.js文件,而不是 模板代码。
webpack 配置react脚手架的更多相关文章
- webpack 配置react脚手架(六):api
1 访问网址 https://cnodejs.org/api 可以调取api 2.//该body-parser 可以将请求的body数据,转变成 json 格式数据://express-session ...
- webpack 配置react脚手架(三):eslint 及优化
首先谨记 eslint的官网: http://eslint.cn/ 1 安装eslint npm i eslint -D 2.在根目录下新建文件 .eslintrc { "extends ...
- webpack 配置react脚手架(二):热更新
下面继续配置 webpack dev server hot module replacement: 首先配置dev-server 安装 npm i webpack-dev-ser ...
- webpack 配置react脚手架(五):mobx
1. 配置项.使用mobx,因为语法时es6-next,所以先配置 .babelrc 文件 { "presets": [ ["es2015", { " ...
- webpack 配置react脚手架(四):路由配置
1. 由于 react-router 是集成了 react-router-dom 和 react-router-native的一起的,所以这里要使用的是 react-router-dom, 2. 安装 ...
- [webpack] 配置react+es6开发环境
写在前面 每次开新项目都要重新安装需要的包,简单记录一下. 以下仅包含最简单的功能: 编译react 编译es6 打包src中入口文件index.js至dist webpack配置react+es6开 ...
- webpack配置React开发环境(上)
Webpack 是一个前端资源加载/打包工具,我们部门的一条主要技术栈就是Webpack+React+ES6+node,虽然之前自己做个人项目也接触好多次Webpack,但是自己并没有研读总结过Web ...
- 使用webpack配置react并添加到flask应用
学习react,配置是很痛苦的一关,虽然现在有了create-react-app这样方便的工具,但是必须要自己配置一遍,才能更好地进行项目开发. 首先要明确一个概念:react的文件必须经过编译才能被 ...
- 基于webpack的react脚手架
一.前言:react的cli开发模式太过于简单,好多东西都要自己配置 二.这里有个简单的配置,可以直接上手开发(不熟悉webpack和npm的绕路),已经完成的配置如下 1:默认ejs模板 2:编译l ...
随机推荐
- 使用自定义Comparator对TreeSet中的数据进行多条件排序
代码记录(需求:根据店铺等级和店铺到某个点的距离进行排序,其中店铺等级由高到低,距离由近及远) 需要排序的对象Store,Store.java package com.zhipengs.work.te ...
- Spring Boot代码生成
一.背景 在Java web开发中,虽然Spring boot已经帮助我们简化了很多工作,但项目中庞杂的业务仍然需要自己去编写较多的 entity,vo,Mapper,Service, Control ...
- 提车应该检查哪?4S店都怕你检查这4个“雷区”,别等后悔才知道
https://mbd.baidu.com/newspage/data/landingsuper?context=%7B%22nid%22%3A%22news_9381645601643691163% ...
- 关于 磁盘 I/O 的工作机制那些事
总有一些你我看不见的东西,存在与你我周围 <深入分析 javaW 技术内幕> 读书感悟 作者 :淮左白衣 写于2018年4月11日19:35:06 写在前面的话 字节与字符的转换桥梁 用户 ...
- Erlang:[笔记二,构建工具rebar之发布应用]
概述 通过rebar可以发布rebar构建的erlang项目,生成可执行的二进制脚本文件,大大降低了执行应用的复杂度.该笔记Erlang环境为Erlang/OTP 19 ,以下适用于Eralng/OT ...
- VirtualBox中CentOS7.2 网络配置(固定IP+联网)(亲测有效)
https://www.linuxidc.com/Linux/2018-04/151924.htm 一.前言 用虚拟机装Linux系统时,经常会出现一些问题.比如:从主机到虚拟机之间网络 ...
- mysql 库表的操作
MySQL的库.表的详细操作 MySQL数据库 本节目录 一 库操作 二 表操作 三 行操作 一 库操作 1.创建数据库 1.1 语法 CREATE DATABASE 数据库名 charset utf ...
- 关于Django ModelForm渲染时间格式问题
关于Django ModelForm渲染时间格式问题 直接定义DateTimeInput或者DateTimeFile是不行的,渲染在html页面中的仍然是Input text类型 解决办法:自定义小部 ...
- Python中下划线的5种含义
目录 单前导下划线 _var 当涉及到变量和方法名称时,单个下划线前缀有一个约定俗成的含义. 它是对程序员的一个提示 - 意味着Python社区一致认为它应该是什么意思,但程序的行为不受影响. 单末尾 ...
- MogileFS与spring结合
一.通过Maven添加MogileFS的Java客户端驱动包 <dependency> <groupId>fm.last</groupId> <artifac ...