react技术栈实践(1)
本文来自网易云社区
作者:汪洋
背景
最近开发一个全新AB测试平台,思考了下正好可以使用react技术开发。
实践前技术准备
首先遇到一个概念,redux。这货还真不好理解,大体的理解:Store包含所有数据,视图触发一个Action,Store收到Action后,返回一个新的 State,这样视图就发生变化,State计算过程叫做 Reducer,Reducer其实就是一个处理数据的函数,接受 Action和 当前State作为参数,返回一个新的 State。
明白这个后,就可以开始实践了。
搭建平台的脚手架
对于我这方面没搞过的菜鸟,还真是不容易。接下来说下作为新手如何实践的。
第一步:依赖包
"devDependencies": {
"babel-core": "^6.26.0",
"babel-eslint": "^8.2.2",
"babel-loader": "^7.1.2",
"babel-plugin-import": "^1.6.6",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"css-loader": "^0.28.7",
"eslint": "^4.18.2",
"eslint-config-airbnb": "^16.1.0",
"eslint-loader": "^2.0.0",
"eslint-plugin-import": "^2.9.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.7.0",
"extract-text-webpack-plugin": "^3.0.2",
"html-webpack-plugin": "^3.0.4",
"less": "^2.7.3",
"less-loader": "^4.0.6",
"style-loader": "^0.19.1",
"url-loader": "^1.0.1",
"webpack": "^3.1.0"},"dependencies": {
"normalize.css": "^8.0.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"redux": "^3.7.2"}dependencies 中引入的依赖包,是react的标配了,不用解释。
devDependencies 中引入了 webpack,babel,babel插件,eslint语法检测,eslint配置包airbnb,html模板资源替换插件 html-webpack-plugin,css提取插件 extract-text-webpack-plugin,less编译相关插件,图片等静态资源路径处理插件 url-loader。
这里作为新手,一般都是参考网上的配置,比如我就是github上找了个项目,摸索一下。推荐一本教程书《React全栈》,作者写的很详细,对入门绝对有帮助。
至此,基本依赖包已加载完。第二步:webpack配置 这里不得不说,新手真不容易。 首先介绍下项目结构:
views/entry.html(静态模板),
src/entry.jsx(入口文件),
src/actions(redux概念中Actions所在的文件夹) ,
src/reducers(redux概念中Reducers所在的文件夹) ,
src/store(redux概念中Store所在的文件夹) ,
src/pages(存放页面的文件夹,jsx),
src/compinents(存放业务组件的文件夹,jsx),
src/style(公共样式文件夹,less),
src/utils(帮助类文件夹),
src/constants(常量所在文件夹,保存各自的actions的type),
src/plugins(第三方插件文件夹),
build/(编译后文件),
webpack/(webpack编译配置所在文件夹),
.eslintrc(eslint配置文件),
.gitignore(git配置文件),
package.json
接下来就是webpack的配置了,先上代码
const path = require('path');const webpack = require('webpack');// html中替换编译后的jsconst HtmlwebpackPlugin = require('html-webpack-plugin');// css提取const ExtractTextPlugin = require('extract-text-webpack-plugin');const ROOT_PATH = path.resolve(__dirname);const APP_PATH = path.resolve(ROOT_PATH, '../src');const BUILD_PATH = path.resolve(ROOT_PATH, '../build');module.exports = {
entry: {
entry: path.resolve(APP_PATH, './entry.jsx'),
vendor: ['react', 'react-dom', 'pace']
},
output: {
filename: '[name].js',
path: BUILD_PATH,
chunkFilename: '[name].js',
publicPath: '../'
},
devtool: 'eval-source-map', module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
query: {
presets: ['es2015', 'react', 'stage-0'],
plugins: ['syntax-dynamic-import', ['import', { libraryName: 'antd', style: 'css' }]]
}
}
]
},
{
test: /\.(css|less)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [ 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]', 'less-loader'
]
}),
exclude: /node_modules/
},
{
test: /\.(css)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [ 'css-loader'
]
}),
include: /node_modules/
},
{
test: /\.(jpg|jpeg|png|svg|gif|bmp)/i,
use: [ 'url-loader?limit=5000&name=img/[name].[sha512:hash:base64:8].[ext]'
]
},
{
test: /\.(woff|woff2|ttf|eot)($|\?)/i,
use: [ 'url-loader?limit=5000&name=fonts/[name].[sha512:hash:base64:8].[ext]'
]
}
]
},
resolve: {
extensions: ['.js', '.jsx', '.less', '.css', '.png', '.jpg', '.svg', '.gif', '.eot'],
alias: {
pace: path.resolve(ROOT_PATH, '../src/plugins/pace/index.js'),
ImagesPath: path.resolve(ROOT_PATH, '../src/')
}
},
devServer: {
historyApiFallback: true,
hot: true,
inline: true,
progress: true
},
plugins: [ new webpack.optimize.CommonsChunkPlugin({
name: ['commons', 'vendor'],
minChunks: 2
}), new ExtractTextPlugin('commons.css', {
allChunks: true
}), new HtmlwebpackPlugin({
template: path.resolve(ROOT_PATH, '../views/entry.html'),
filename: path.resolve(ROOT_PATH, '../build/entry.html'),
chunks: ['entry', 'vendor'],
hash: false
}), // 加署名
new webpack.BannerPlugin('Copyright by xxx')
]
};
第一次接触配置,真的找不到北,太多插件,太多功能。作为新手,那需要怎么个思路,我总结:按项目需求来配置。不要认为其他人配置的就适合自己项目,要不然给自己带来各种麻烦。 摸索这个过程还挺长的:
A. 首先需求还是明确的:less编译、jsx编译、公共文件单独打包、html静态模板中插入编译后的文件路径、css提取。 上面这些对应配置:
const path = require('path');const webpack = require('webpack');// html中替换编译后的jsconst HtmlwebpackPlugin = require('html-webpack-plugin');// css提取const ExtractTextPlugin = require('extract-text-webpack-plugin');const ROOT_PATH = path.resolve(__dirname);const APP_PATH = path.resolve(ROOT_PATH, '../src');const BUILD_PATH = path.resolve(ROOT_PATH, '../build');module.exports = {
entry: {
entry: path.resolve(APP_PATH, './entry.jsx'),
vendor: ['react', 'react-dom', 'pace']
},
output: {
filename: '[name].js',
path: BUILD_PATH,
chunkFilename: '[name].js',
publicPath: '../'
},
devtool: 'eval-source-map', module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
query: {
presets: ['es2015', 'react', 'stage-0']
}
}
]
},
{
test: /\.(css|less)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [ 'css-loader', 'less-loader'
]
}),
exclude: /node_modules/
},
{
test: /\.(jpg|jpeg|png|svg|gif|bmp)/i,
use: [ 'url-loader?limit=5000&name=img/[name].[sha512:hash:base64:8].[ext]'
]
},
{
test: /\.(woff|woff2|ttf|eot)($|\?)/i,
use: [ 'url-loader?limit=5000&name=fonts/[name].[sha512:hash:base64:8].[ext]'
]
}
]
},
plugins: [ new webpack.optimize.CommonsChunkPlugin({
name: ['commons', 'vendor'],
minChunks: 2
}), new ExtractTextPlugin('commons.css', {
allChunks: true
}), new HtmlwebpackPlugin({
template: path.resolve(ROOT_PATH, '../views/entry.html'),
filename: path.resolve(ROOT_PATH, '../build/entry.html'),
chunks: ['entry', 'vendor'],
hash: false
})
]
};
B. 配置到这步后,就能满足基本开发了。试用之后,这时候对自己提出了几个问题:
命名css,开发的时候能不能不用担心命名冲突的问题。
css中引入图片后,编译失败问题。
第三方插件 加载效果pace组件,引入问题。
现在文件过大,有根据路由按需加载需求。
针对上面4个问题,重新配置:
第2个和3个解决方案一致:即声明别名
resolve: {
extensions: ['.js', '.jsx', '.less', '.css', '.png', '.jpg', '.svg', '.gif', '.eot'],
alias: {
pace: path.resolve(ROOT_PATH, '../src/plugins/pace/index.js'),
ImagesPath: path.resolve(ROOT_PATH, '../src/')
}
}
当中第3个问题,网上找了好多资料,都没有结果,后来请教了前端群的同行,才解决该问题。
解决第1个问题过程中,我学习到了cssModule的概念,一开始菜鸟还不好理解,实践了后,还真是个好东西。
{
test: /\.(css|less)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [ 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]', 'less-loader'
]
}),
exclude: /node_modules/
},
只要css-loader启动modules就好了。为了支持 react,引入了 react-css-modules 依赖包。
网易云免费体验馆,0成本体验20+款云产品
更多网易研发、产品、运营经验分享请访问网易云社区。
相关文章:
【推荐】 git 常用命令
【推荐】 接口文档神器Swagger(上篇)
react技术栈实践(1)的更多相关文章
- react技术栈实践(2)
本文来自网易云社区 作者:汪洋 这时候还没完,又有两个问题引出来了. 按照上面的配置,第三方库 antd 竟然也被编译了,导致样式失败. react中,一旦包裹了子组件,子组件没办法直接使用 styl ...
- 重谈react优势——react技术栈回顾
react刚刚推出的时候,讲react优势搜索结果是几十页. 现在,react已经慢慢退火,该用用react技术栈的已经使用上,填过多少坑,加过多少班,血泪控诉也不下千文. 今天,再谈一遍react优 ...
- node.js+react全栈实践-Form中按照指定路径上传文件并
书接上回,讲到“使用同一个新增弹框”中有未解决的问题,比如复杂的字段,文件,图片上传,这一篇就解决文件上传的问题.这里的场景是在新增弹出框中要上传一个图片,并且这个上传组件放在一个Form中,和其他文 ...
- node.js+react全栈实践
利用业余时间写了个简单的项目,使用react+node.js做的一个全栈实践项目,前端参考了[React-Admin-Starter](https://github.com/veryStarters/ ...
- 深入React技术栈之初入React世界
1.1 react简介 react并不是完整的MVM/MVVM框架,专注于提供清晰.简洁的View层解决方案. 传统开发模式,要更新页面需要手动操作DOM元素.如图1.1所示,React在DOM上封装 ...
- React技术栈梳理
一.react是什么? react是一个js框架,可以用它来编写html页面,使用react后我们可以完全抛弃html(只需要一个主index文件),而用纯js来编写页面: 二.为什么要使用react ...
- 深入react技术栈解读
1. react实现virtual DOM ,如果要改变页面的内容,还是需要执行DOM操作,比原生操作DOM多了virtualDOM的操作(计算,对比等), 应该是更耗性能??? 2. react特点 ...
- 深入React技术栈之setState详解
抛出问题 class Example extends Component { contructor () { super() this.state = { value: 0, index: 0 } } ...
- React技术栈——Redux
Redux 1.Redux是什么? Redux对于JavaScript应用而言是一个可预测状态的容器.换言之,它是一个应用数据流框架,而不是传统的像underscore.js或者AngularJs ...
随机推荐
- JAVA的API部分介绍
个人理解: Object作为最大的父类,里面存在不少方法,可以在API中具体的查找.比如可以帮助查看是否相同的equals方法,不过要想看具体属性是否相同需要得重写,打印.调用对象相当于调用其tost ...
- ES6学习(2)
Set和Map数据结构 ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set 数据结构. const s = new ...
- SQL Server 填充因子
在创建聚集索引时,表中的数据按照索引列中的值的顺序存储在数据库的数据页中.在表中插入新的数据行或更改索引列中的值时,Microsoft® SQL Server™ 2000 可能必须重新 ...
- HDU 4283 You Are the One (区间DP,经典)
题意: 某校举行一场非诚勿扰,给定一个出场序列,表示n个人的屌丝值,如果他是第k个出场的,他的不满意度为(k-1)*diao[i].为了让所有人的屌丝值之和更小,导演设置一个栈,可以将部分人装进栈中, ...
- 2017年团体程序设计天梯赛 - 大区赛 L3-3
题意:有向图找哈密顿回路 比赛的时候剪枝只剪了vis 状压没剪对 反而只拿17分... 比赛结束后还去看了一发这个NP问题的QB(快速回溯法...但是对于本题好像大材小用...) 上网看了一个神犇的写 ...
- Servlet中的属性(attribute)和参数(parameter)的区别
1.引子 初学者对属性(attribute)和参数(parameter)容易搞混.没搞清他们的区别,项目中就可能出现一此莫名其妙的问题. 2.两者的区别 1) 属性(attribute) 属性是在后台 ...
- 斐讯k2p 月光银 硬件版本A2-软件版本22.7.8.5 刷官改系统
Mark https://huabuyu.net/斐讯k2p%20月光银%20硬件版本A2-软件版本22.7.8.5%20刷官改系统.html 详细资源推荐:恩山论坛 https://www.righ ...
- Java的引用StrongReference、 SoftReference、 WeakReference 、PhantomReference
1. Strong Reference StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收 @Te ...
- 如何将oracle查询的结果传输给变量
如何将oracle查询的结果传输给变量 1. sqlplus查询时的变量设置 set echo off; #控制start命令不列出命令文件中的每一命令 set feedback off; #显示由查 ...
- Typescript学习(一)----准备篇(vscode编译ts文件)
什么是typescript? typescript是微软开发的一个脚本语言.他是JavaScript的超级,他遵循es6语法规范,他扩展了JavaScript的语法. 理解es5,es6,javasc ...