react 环境 全家桶
brickspert commented on 2 Sep 2017 •
edited
从零搭建React全家桶框架教程源码地址:https://github.com/brickspert/react-family 大家阅读的时候,照着目录来阅读哦,有些章节不在文章里面。要点链接的~目录
写在前面当我第一次跟着项目做 做项目,总是要解决各种问题的,所以每个地方都需要去了解,但是对整个框架没有一个整体的了解,实在是不行。 期间,我也跟着别人的搭建框架的教程一步一步的走,但是经常因为自己太菜,走不下去。在经过各种蹂躏之后,对整个框架也有一个大概的了解, 我的这个教程,从新建根文件夹开始,到成型的框架,每个文件为什么要建立?建立了干什么?每个依赖都是干什么的?一步一步写下来,供大家学习。 当然,这个框架我以后会一直维护的,也希望大家能一起来完善这个框架,如果您有任何建议,欢迎在这里留言,欢迎 我基于该框架 说明
cd src/pages mkdir Home
│ .babelrc #babel配置文件 │ package-lock.json │ package.json │ README.MD │ webpack.config.js #webpack生产配置文件 │ webpack.dev.config.js #webpack开发配置文件 │ ├─dist ├─public #公共资源文件 └─src #项目源码│ index.html #index.html模板│ index.js #入口文件│ ├─component #组建库│ └─Hello│ Hello.js│ ├─pages #页面目录│ ├─Counter│ │ Counter.js│ │ │ ├─Home│ │ Home.js│ │ │ ├─Page1│ │ │ Page1.css #页面样式│ │ │ Page1.js│ │ │ │ │ └─images #页面图片│ │ brickpsert.jpg│ │ │ └─UserInfo│ UserInfo.js│ ├─redux│ │ reducers.js│ │ store.js│ │ │ ├─actions│ │ counter.js│ │ userInfo.js│ │ │ ├─middleware│ │ promiseMiddleware.js│ │ │ └─reducers│ counter.js│ userInfo.js│ └─router #路由文件Bundle.jsrouter.js init项目
webpack
babel
通俗的说,就是我们可以用ES6, ES7等来编写代码,Babel会把他们统统转为ES5。
新建
{"presets": ["es2015","react","stage-0"],"plugins": []} 修改 /*src文件夹下面的以.js结尾的文件,要使用babel解析*//*cacheDirectory是用来缓存编译结果,下次编译加速*/module: {rules: [{test: /\.js$/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, 'src')}]} 现在我们简单测试下,是否能正确转义ES6~ 修改 /*使用es6的箭头函数*/var func = str => {document.getElementById('app').innerHTML = str;};func('我现在在使用Babel!'); 执行打包命令 浏览器打开 然后我们打开打包后的 Q: A: 每一级包含上一级的功能,比如 参考地址:
react
修改 import React from 'react'; import ReactDom from 'react-dom';ReactDom.render(<div>Hello React!</div>, document.getElementById('app')); 执行打包命令 打开 我们简单做下改进,把 cd src mkdir component cd component mkdir Hello cd Hello touch Hello.js 按照React语法,写一个Hello组件 import React, {Component} from 'react';export default class Hello extends Component {render() {return (<div>Hello,React!</div>)} } 然后让我们修改
import React from 'react'; import ReactDom from 'react-dom'; import Hello from './component/Hello/Hello';ReactDom.render(<Hello/>, document.getElementById('app')); 在根目录执行打包命令
打开 命令优化Q:每次打包都得在根目录执行这么一长串命令 A:修改
"scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev-build": "webpack --config webpack.dev.config.js"} 现在我们打包只需要执行 参考地址: http://www.ruanyifeng.com/blog/2016/10/npm_scripts.html react-router
新建
按照
import React from 'react';import {BrowserRouter as Router, Route, Switch, Link} from 'react-router-dom';import Home from '../pages/Home/Home'; import Page1 from '../pages/Page1/Page1';const getRouter = () => (<Router><div><ul><li><Link to="/">首页</Link></li><li><Link to="/page1">Page1</Link></li></ul><Switch><Route exact path="/" component={Home}/><Route path="/page1" component={Page1}/></Switch></div></Router> );export default getRouter; 新建页面文件夹
新建两个页面
填充内容:
import React, {Component} from 'react';export default class Home extends Component {render() {return (<div>this is home~</div>)} } Page1.js import React, {Component} from 'react';export default class Page1 extends Component {render() {return (<div>this is Page1~</div>)} } 现在路由和页面建好了,我们在入口文件 修改 import React from 'react'; import ReactDom from 'react-dom';import getRouter from './router/router';ReactDom.render(getRouter(), document.getElementById('app')); 现在执行打包命令 那么问题来了~我们发现点击‘首页’和‘Page1’没有反应。不要惊慌,这是正常的。 我们之前一直用这个路径访问
下一节,我们来使用第二种方法启动服务器。这一节的DEMO,先放这里。 参考地址
webpack-dev-server简单来说,
修改
devServer: {contentBase: path.join(__dirname, './dist')} 现在执行
浏览器打开http://localhost:8080,OK,现在我们可以点击 Q: A: 重要提示:webpack-dev-server编译后的文件,都存储在内存中,我们并不能看见的。你可以删除之前遗留的文件 每次执行 "scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev-build": "webpack --config webpack.dev.config.js","start": "webpack-dev-server --config webpack.dev.config.js"} 下次执行 既然用到了
proxy: {"/api": "http://localhost:3000"}
根据这几个配置,修改下我们的
devServer: {port: 8080,contentBase: path.join(__dirname, './dist'),historyApiFallback: true,host: '0.0.0.0'}
"dev": "webpack-dev-server --config webpack.dev.config.js --color --progress" 现在我们执行 参考地址:
模块热替换(Hot Module Replacement)到目前,当我们修改代码的时候,浏览器会自动刷新,不信你可以去试试。(如果你的不会刷新,看看这个调整文本编辑器) 我相信看这个教程的人,应该用过别人的框架。我们在修改代码的时候,浏览器不会刷新,只会更新自己修改的那一块。我们也要实现这个效果。 我们看下webpack模块热替换教程。 我们接下来要这么修改
"dev": "webpack-dev-server --config webpack.dev.config.js --color --progress --hot"
import React from 'react'; import ReactDom from 'react-dom';import getRouter from './router/router';if (module.hot) {module.hot.accept(); }ReactDom.render(getRouter(), document.getElementById('app')); 现在我们执行 做模块热替换,我们只改了几行代码,非常简单的。纸老虎一个~ 现在我需要说明下我们命令行使用的 const webpack = require('webpack');devServer: {hot: true }plugins:[new webpack.HotModuleReplacementPlugin() ]
你以为模块热替换到这里就结束了?no 上面的配置对 例如下面的 修改
import React, {Component} from 'react';export default class Home extends Component {constructor(props) {super(props);this.state = {count: 0}}_handleClick() {this.setState({count: ++this.state.count});}render() {return (<div>this is home~<br/>当前计数:{this.state.count}<br/><button onClick={() => this._handleClick()}>自增</button></div>)} } 你可以测试一下,当我们修改代码的时候, 为了在 Q: 请问 A: 区别在于 下面我们来加入 安装依赖
根据文档,
{"presets": ["es2015","react","stage-0"],"plugins": ["react-hot-loader/babel"] }
entry: ['react-hot-loader/patch',path.join(__dirname, 'src/index.js')]
import React from 'react'; import ReactDom from 'react-dom'; import {AppContainer} from 'react-hot-loader';import getRouter from './router/router';/*初始化*/ renderWithHotReload(getRouter());/*热更新*/ if (module.hot) {module.hot.accept('./router/router', () => {const getRouter = require('./router/router').default;renderWithHotReload(getRouter());}); }function renderWithHotReload(RootElement) {ReactDom.render(<AppContainer>{RootElement}</AppContainer>,document.getElementById('app')) } 现在,执行 参考文章:
文件路径优化做到这里,我们简单休息下。做下优化~ 在之前写的代码中,我们引用组件,或者页面时候,写的是相对路径~ 比如 import Home from '../pages/Home/Home'; webpack提供了一个别名配置,就是我们无论在哪个路径下,引用都可以这样 import Home from 'pages/Home/Home'; 下面我们来配置下,修改
resolve: {alias: {pages: path.join(__dirname, 'src/pages'),component: path.join(__dirname, 'src/component'),router: path.join(__dirname, 'src/router')}} 然后我们把之前使用的绝对路径统统改掉。
import Home from 'pages/Home/Home'; import Page1 from 'pages/Page1/Page1';
import getRouter from 'router/router'; 我们这里约定,下面,我们会默认配置需要的别名路径,不再做重复的讲述哦。 redux接下来,我们就要就要就要集成 要对 如果要对 不要被各种关于 reducers, middleware, store 的演讲所蒙蔽 ---- Redux 实际是非常简单的。 当然,我这篇文章是写给新手的,如果看不懂上面的文章,或者不想看,没关系。先会用,多用用就知道原理了。 开始整代码!我们就做一个最简单的计数器。自增,自减,重置。 先安装 初始化目录结构 cd src mkdir redux cd redux mkdir actions mkdir reducers touch reducers.js touch store.js touch actions/counter.js touch reducers/counter.js 先来写 /*action*/export const INCREMENT = "counter/INCREMENT"; export const DECREMENT = "counter/DECREMENT"; export const RESET = "counter/RESET";export function increment() {return {type: INCREMENT} }export function decrement() {return {type: DECREMENT} }export function reset() {return {type: RESET} } 再来写
import {INCREMENT, DECREMENT, RESET} from '../actions/counter';/* * 初始化state */const initState = {count: 0 }; /* * reducer */ export default function reducer(state = initState, action) {switch (action.type) {case INCREMENT:return {count: state.count + 1};case DECREMENT:return {count: state.count - 1};case RESET:return {count: 0};default:return state} } 一个项目有很多的
import counter from './reducers/counter';export default function combineReducers(state = {}, action) {return {counter: counter(state.counter, action)} } 到这里,我们必须再理解下一句话。
看看上面的代码,无论是 接下来,我们要创建一个 前面我们可以使用 还可以使用 那我们如何提交
import {createStore} from 'redux'; import combineReducers from './reducers.js';let store = createStore(combineReducers);export default store; 到现在为止,我们已经可以使用 下面我们就简单的测试下 cd src cd redux touch testRedux.js
import {increment, decrement, reset} from './actions/counter';import store from './store';// 打印初始状态 console.log(store.getState());// 每次 state 更新时,打印日志 // 注意 subscribe() 返回一个函数用来注销监听器 let unsubscribe = store.subscribe(() =>console.log(store.getState()) );// 发起一系列 action store.dispatch(increment()); store.dispatch(decrement()); store.dispatch(reset());// 停止监听 state 更新 unsubscribe(); 当前文件夹执行命令
是不是看到输出了
做这个测试,就是为了告诉大家, 到这里,我建议你再理下
就是酱紫~~ 这会
alias: {...actions: path.join(__dirname, 'src/redux/actions'),reducers: path.join(__dirname, 'src/redux/reducers'),redux: path.join(__dirname, 'src/redux')} 把前面的相对路径都改改。 下面我们开始搭配 写一个
import React, {Component} from 'react';export default class Counter extends Component {render() {return (<div><div>当前计数为(显示redux计数)</div><button onClick={() => {console.log('调用自增函数');}}>自增</button><button onClick={() => {console.log('调用自减函数');}}>自减</button><button onClick={() => {console.log('调用重置函数');}}>重置</button></div>)} } 修改路由,增加
import React from 'react';import {BrowserRouter as Router, Route, Switch, Link} from 'react-router-dom';import Home from 'pages/Home/Home'; import Page1 from 'pages/Page1/Page1'; import Counter from 'pages/Counter/Counter';const getRouter = () => (<Router><div><ul><li><Link to="/">首页</Link></li><li><Link to="/page1">Page1</Link></li><li><Link to="/counter">Counter</Link></li></ul><Switch><Route exact path="/" component={Home}/><Route path="/page1" component={Page1}/><Route path="/counter" component={Counter}/></Switch></div></Router> );export default getRouter;
下一步,我们让 当然我们可以使用刚才测试
先来安装
import React, {Component} from 'react'; import {increment, decrement, reset} from 'actions/counter';import {connect} from 'react-redux';class Counter extends Component {render() {return (<div><div>当前计数为{this.props.counter.count}</div><button onClick={() => this.props.increment()}>自增</button><button onClick={() => this.props.decrement()}>自减</button><button onClick={() => this.props.reset()}>重置</button></div>)} }const mapStateToProps = (state) => {return {counter: state.counter} };const mapDispatchToProps = (dispatch) => {return {increment: () => {dispatch(increment())},decrement: () => {dispatch(decrement())},reset: () => {dispatch(reset())}} };export default connect(mapStateToProps, mapDispatchToProps)(Counter); 下面我们要传入
import React from 'react'; import ReactDom from 'react-dom'; import {AppContainer} from 'react-hot-loader'; import {Provider} from 'react-redux'; import store from './redux/store';import getRouter from 'router/router';/*初始化*/ renderWithHotReload(getRouter());/*热更新*/ if (module.hot) {module.hot.accept('./router/router', () => {const getRouter = require('router/router').default;renderWithHotReload(getRouter());}); }function renderWithHotReload(RootElement) {ReactDom.render(<AppContainer><Provider store={store}>{RootElement}</Provider></AppContainer>,document.getElementById('app')) } 到这里我们就可以执行 但是你发现 ERROR in ./node_modules/react-redux/es/connect/mapDispatchToProps.js Module not found: Error: Can't resolve 'redux' in 'F:\Project\react\react-family\node_modules\react-redux\es\connect' ERROR in ./src/redux/store.js Module not found: Error: Can't resolve 'redux' in 'F:\Project\react\react-family\src\redux' WTF?这个错误困扰了半天。我说下为什么造成这个错误。我们引用
然而,我们在 resolve: {alias: {...redux: path.join(__dirname, 'src/redux')}} 然后 现在你可以 这里我们再缕下(可以读React 实践心得:react-redux 之 connect 方法详解)
接下来,我们要说异步 参考地址: http://cn.redux.js.org/docs/advanced/AsyncActions.html 想象一下我们调用一个异步
下面,我们以向后台请求用户基本信息为例。
cd dist mkdir api cd api touch user.json
{"name": "brickspert","intro": "please give me a star" }
cd src/redux/actions touch userInfo.js
export const GET_USER_INFO_REQUEST = "userInfo/GET_USER_INFO_REQUEST"; export const GET_USER_INFO_SUCCESS = "userInfo/GET_USER_INFO_SUCCESS"; export const GET_USER_INFO_FAIL = "userInfo/GET_USER_INFO_FAIL";function getUserInfoRequest() {return {type: GET_USER_INFO_REQUEST} }function getUserInfoSuccess(userInfo) {return {type: GET_USER_INFO_SUCCESS,userInfo: userInfo} }function getUserInfoFail() {return {type: GET_USER_INFO_FAIL} } 我们创建了请求中,请求成功,请求失败三个
再强调下, cd src/redux/reducers touch userInfo.js
import {GET_USER_INFO_REQUEST, GET_USER_INFO_SUCCESS, GET_USER_INFO_FAIL} from 'actions/userInfo';const initState = {isLoading: false,userInfo: {},errorMsg: '' };export default function reducer(state = initState, action) {switch (action.type) {case GET_USER_INFO_REQUEST:return {...state,isLoading: true,userInfo: {},errorMsg: ''};case GET_USER_INFO_SUCCESS:return {...state,isLoading: false,userInfo: action.userInfo,errorMsg: ''};case GET_USER_INFO_FAIL:return {...state,isLoading: false,userInfo: {},errorMsg: '请求错误'};default:return state;} } 这里的 组合
import counter from 'reducers/counter'; import userInfo from 'reducers/userInfo';export default function combineReducers(state = {}, action) {return {counter: counter(state.counter, action),userInfo: userInfo(state.userInfo, action)} }
export function getUserInfo() {return function (dispatch) {dispatch(getUserInfoRequest());return fetch('http://localhost:8080/api/user.json').then((response => {return response.json()})).then((json) => {dispatch(getUserInfoSuccess(json))}).catch(() => {dispatch(getUserInfoFail());})} } 我们这里发现,别的 {type: xxxx} 但是我们现在的这个 为了让
这里涉及到 简单的说,中间件就是 我们来引入
import {createStore, applyMiddleware} from 'redux'; import thunkMiddleware from 'redux-thunk'; import combineReducers from './reducers.js';let store = createStore(combineReducers, applyMiddleware(thunkMiddleware));export default store; 到这里, cd src/pages mkdir UserInfo cd UserInfo touch UserInfo.js
import React, {Component} from 'react'; import {connect} from 'react-redux'; import {getUserInfo} from "actions/userInfo";class UserInfo extends Component {render() {const {userInfo, isLoading, errorMsg} = this.props.userInfo;return (<div>{isLoading ? '请求信息中......' :(errorMsg ? errorMsg :<div><p>用户信息:</p><p>用户名:{userInfo.name}</p><p>介绍:{userInfo.intro}</p></div>)}<button onClick={() => this.props.getUserInfo()}>请求用户信息</button></div>)} }export default connect((state) => ({userInfo: state.userInfo}), {getUserInfo})(UserInfo); 这里你可能发现 增加路由 import React from 'react';import {BrowserRouter as Router, Route, Switch, Link} from 'react-router-dom';import Home from 'pages/Home/Home'; import Page1 from 'pages/Page1/Page1'; import Counter from 'pages/Counter/Counter'; import UserInfo from 'pages/UserInfo/UserInfo';const getRouter = () => (<Router><div><ul><li><Link to="/">首页</Link></li><li><Link to="/page1">Page1</Link></li><li><Link to="/counter">Counter</Link></li><li><Link to="/userinfo">UserInfo</Link></li></ul><Switch><Route exact path="/" component={Home}/><Route path="/page1" component={Page1}/><Route path="/counter" component={Counter}/><Route path="/userinfo" component={UserInfo}/></Switch></div></Router> );export default getRouter; 现在你可以执行 到这里 combinReducers优化
import {combineReducers} from "redux";import counter from 'reducers/counter'; import userInfo from 'reducers/userInfo';export default combineReducers({counter,userInfo }); devtool优化现在我们发现一个问题,代码哪里写错了,浏览器报错只报在 这让我们分析错误无从下手。看这里。 我们增加
devtool: 'inline-source-map' 这次看错误信息是不是提示的很详细了? 同时,我们在 编译css先说这里为什么不用
{test: /\.css$/,use: ['style-loader', 'css-loader'] } 我们用 cd src/pages/Page1 touch Page1.css
.page-box {border: 1px solid red; }
import React, {Component} from 'react';import './Page1.css';export default class Page1 extends Component {render() {return (<div className="page-box">this is page1~</div>)} } 好了,现在 编译图片
{test: /\.(png|jpg|gif)$/,use: [{loader: 'url-loader',options: {limit: 8192}}] }
我们来用 cd src/pages/Page1 mkdir images 给 修改代码,引用图片
import React, {Component} from 'react';import './Page1.css';import image from './images/brickpsert.jpg';export default class Page1 extends Component {render() {return (<div className="page-box">this is page1~<img src={image}/></div>)} } 可以去看看效果啦。 按需加载为什么要实现按需加载? 我们现在看到,打包完后,所有页面只生成了一个 如果每个页面都打包了自己单独的JS,在进入自己页面的时候才加载对应的js,那首屏加载就会快很多哦。 在 在4.0版本,官方放弃了这种处理按需加载的方式,选择了一个更加简洁的处理方式。 传送门 根据官方示例,我们开搞
cd src/router touch Bundle.js
import React, {Component} from 'react'class Bundle extends Component {state = {// short for "module" but that's a keyword in js, so "mod"mod: null};componentWillMount() {this.load(this.props)}componentWillReceiveProps(nextProps) {if (nextProps.load !== this.props.load) {this.load(nextProps)}}load(props) {this.setState({mod: null});props.load((mod) => {this.setState({// handle both es imports and cjsmod: mod.default ? mod.default : mod})})}render() {return this.props.children(this.state.mod)} }export default Bundle;
import React from 'react';import {BrowserRouter as Router, Route, Switch, Link} from 'react-router-dom';import Bundle from './Bundle';import Home from 'bundle-loader?lazy&name=home!pages/Home/Home'; import Page1 from 'bundle-loader?lazy&name=page1!pages/Page1/Page1'; import Counter from 'bundle-loader?lazy&name=counter!pages/Counter/Counter'; import UserInfo from 'bundle-loader?lazy&name=userInfo!pages/UserInfo/UserInfo';const Loading = function () {return <div>Loading...</div> };const createComponent = (component) => (props) => (<Bundle load={component}>{(Component) => Component ? <Component {...props} /> : <Loading/>}</Bundle> );const getRouter = () => (<Router><div><ul><li><Link to="/">首页</Link></li><li><Link to="/page1">Page1</Link></li><li><Link to="/counter">Counter</Link></li><li><Link to="/userinfo">UserInfo</Link></li></ul><Switch><Route exact path="/" component={createComponent(Home)}/><Route path="/page1" component={createComponent(Page1)}/><Route path="/counter" component={createComponent(Counter)}/><Route path="/userinfo" component={createComponent(UserInfo)}/></Switch></div></Router> );export default getRouter; 现在你可以 但是你可能发现,名字都是 我们修改下 output: {path: path.join(__dirname, './dist'),filename: 'bundle.js',chunkFilename: '[name].js'} 现在你运行发现名字变成 那么问题来了 其实在这里我们定义了,
看到没。这里有个 参考地址:
缓存想象一下这个场景~ 我们网站上线了,用户第一次访问首页,下载了 这肯定不行呀,所以我们一般都会做一个缓存,用户下载一次 有一天,我们更新了 怎么解决?每次代码更新后,打包生成的名字不一样。比如第一次叫 文档看这里 我们照着文档来
output: {path: path.join(__dirname, './dist'),filename: '[name].[hash].js',chunkFilename: '[name].[chunkhash].js'} 每次打包都用增加 现在我们试试,是不是修改了文件,打包后相应的文件名字就变啦? 但是你可能发现了,网页打开报错了~因为你 啊~那岂不是我每次编译打包,都得去改一下js名字?欲知后事如何,且看下节分享。 HtmlWebpackPlugin这个插件,每次会自动把js插入到你的模板
新建模板 cd src touch index.html
<!doctype html> <html lang="en"> <head><meta charset="UTF-8"><title>Document</title> </head> <body> <div id="app"></div> </body> </html> 修改 var HtmlWebpackPlugin = require('html-webpack-plugin');plugins: [new HtmlWebpackPlugin({filename: 'index.html',template: path.join(__dirname, 'src/index.html')})],
说明一下: 提取公共代码想象一下,我们的主文件,原来的 我们把
var webpack = require('webpack');entry: {app: ['react-hot-loader/patch',path.join(__dirname, 'src/index.js')],vendor: ['react', 'react-router-dom', 'redux', 'react-dom', 'react-redux']}/*plugins*/new webpack.optimize.CommonsChunkPlugin({name: 'vendor'}) 把 但是你现在可能发现编译生成的文件 output: {path: path.join(__dirname, './dist'),filename: '[name].[hash].js', //这里应该用chunkhash替换hashchunkFilename: '[name].[chunkhash].js'} 但是无奈,如果用 现在我们在配置开发版配置文件,就向 生产坏境构建
文档看这里 我们要开始做了~ touch webpack.config.js 在
const path = require('path'); var HtmlWebpackPlugin = require('html-webpack-plugin'); var webpack = require('webpack');module.exports = {devtool: 'cheap-module-source-map',entry: {app: [path.join(__dirname, 'src/index.js')],vendor: ['react', 'react-router-dom', 'redux', 'react-dom', 'react-redux']},output: {path: path.join(__dirname, './dist'),filename: '[name].[chunkhash].js',chunkFilename: '[name].[chunkhash].js'},module: {rules: [{test: /\.js$/,use: ['babel-loader'],include: path.join(__dirname, 'src')}, {test: /\.css$/,use: ['style-loader', 'css-loader']}, {test: /\.(png|jpg|gif)$/,use: [{loader: 'url-loader',options: {limit: 8192}}]}]},plugins: [new HtmlWebpackPlugin({filename: 'index.html',template: path.join(__dirname, 'src/index.html')}),new webpack.optimize.CommonsChunkPlugin({name: 'vendor'})],resolve: {alias: {pages: path.join(__dirname, 'src/pages'),component: path.join(__dirname, 'src/component'),router: path.join(__dirname, 'src/router'),actions: path.join(__dirname, 'src/redux/actions'),reducers: path.join(__dirname, 'src/redux/reducers')}} }; 在
然后执行 接下来我们还是要优化正式版配置文件~ 文件压缩
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')module.exports = {plugins: [new UglifyJSPlugin()] }
指定环境
module.exports = {plugins: [new webpack.DefinePlugin({'process.env': {'NODE_ENV': JSON.stringify('production')}})] }
优化缓存刚才我们把 但是现在又有一个问题了。 你随便修改代码一处,例如 官方文档推荐了一个插件HashedModuleIdsPlugin plugins: [new webpack.HashedModuleIdsPlugin()] 现在你打包,修改代码再试试,是不是名字不变啦?错了,现在打包,我发现名字还是变了,经过比对文档,我发现还要加一个 new webpack.optimize.CommonsChunkPlugin({name: 'runtime' }) 加上这句话就好了~为什么呢?看下解释。 注意,引入顺序在这里很重要。CommonsChunkPlugin 的 'vendor' 实例,必须在 'runtime' 实例之前引入。 public path想象一个场景,我们的静态文件放在了单独的静态服务器上去了,那我们打包的时候,如何让静态文件的链接定位到静态服务器呢? 看文档Public Path
output: {publicPath : '/'} 打包优化你现在打开
const CleanWebpackPlugin = require('clean-webpack-plugin');plugins: [new CleanWebpackPlugin(['dist']) ] 现在 抽取css目前我们的 我们使用extract-text-webpack-plugin来实现。
const ExtractTextPlugin = require("extract-text-webpack-plugin");module.exports = {module: {rules: [{test: /\.css$/,use: ExtractTextPlugin.extract({fallback: "style-loader",use: "css-loader"})}]},plugins: [new ExtractTextPlugin({filename: '[name].[contenthash:5].css',allChunks: true})] }
使用 |
brickspert commented on 4 Sep 2017 •
edited
合并提取 |
STMU1320 commented on 4 Sep 2017
博主在打包这里没有讲清楚,webpack没有全局安装的话 webpack --config webpack.dev.config.js 命令会出错。要么全局安装,要么运行命令./node_modules/.bin/webpack --config webpack.dev.config.js |
brickspert commented on 4 Sep 2017
@STMU1320 确实是,sorry。没注意~~ 谢谢谢谢。 |
brickspert commented on 4 Sep 2017
优化目录结构并增加404页面现在我们优化下目录结构,把
import React, {Component} from 'react';import Nav from 'components/Nav/Nav'; import getRouter from 'router/router';export default class App extends Component {render() {return (<div><Nav/>{getRouter()}</div>)} }
import React from 'react'; import ReactDom from 'react-dom'; import {AppContainer} from 'react-hot-loader'; import {Provider} from 'react-redux'; import store from './redux/store'; import {BrowserRouter as Router} from 'react-router-dom'; import App from 'components/App/App';renderWithHotReload(App);if (module.hot) {module.hot.accept('components/App/App', () => {const NextApp = require('components/App/App').default;renderWithHotReload(NextApp);}); }function renderWithHotReload(RootElement) {ReactDom.render(<AppContainer><Provider store={store}><Router><RootElement/></Router></Provider></AppContainer>,document.getElementById('app')) }
import NotFound from 'bundle-loader?lazy&name=notFound!pages/NotFound/NotFound';<Route component={createComponent(NotFound)}/> |
surpass-wei commented on 6 Sep 2017
命令优化 处,应该是执行 |
brickspert commented on 6 Sep 2017
@surpass-wei 哈哈哈哈哈。谢谢谢谢。。已经改了。 之前我的 |
yeliping commented on 7 Sep 2017
一般运行我建议,npm run dev, 发布测试版本包交npm run testbuild,正式版本叫npm run build。这样挺好 |
brickspert commented on 7 Sep 2017
@yeliping 我看别人写的,基本一般运行都是 |
yeliping commented on 7 Sep 2017
我公司的vue框架,不是我搭的。在npm run testbuild和npm run build有区别的,区别就在于,打包了测试和正式环境,那些接口地址就不一样。免得混淆,测试地址上了正式地址的错误。楼主你那个打包压缩没弄错zip这种格式吧 |
brickspert commented on 7 Sep 2017
@yeliping 打包压缩不是打包压缩成zip呀。。。没有这一步。 压缩是指代码压缩~ |
yeliping commented on 7 Sep 2017
我知道是指代码压缩呀,弄错zip这些可以再配置的 |
brickspert commented on 7 Sep 2017
@yeliping 恩恩。下一步 我可以做这个。嘿嘿。 |
yeliping commented on 7 Sep 2017 •
edited
`'use strict'; var exports = {
}; module.exports = exports;` 这个文件就是用来配置测试环境或者正式环境。主要是以前有个新同事把测试发到正式,导致出现大问题.所以他们弄了这样的配置 |
brickspert commented on 7 Sep 2017
@yeliping 我们开发时就没个问题的。可以把 |
brickspert commented on 7 Sep 2017
@yeliping 当然因项目而异啦。 |
ranjin commented on 7 Sep 2017 •
edited
在
|
brickspert commented on 7 Sep 2017
@ranjin 祝你好运。 |
ranjin commented on 7 Sep 2017
也就是说 如果配置的是 |
brickspert commented on 7 Sep 2017
@ranjin 可以加,也可以不加。 如果不加的话 就默认8080哦。 |
surpass-wei commented on 7 Sep 2017
向后台请求用户基本信息为例的例子中,一会是 |
brickspert commented on 7 Sep 2017
@surpass-wei 确实是写错了。已经修正。谢谢你。 |
ranjin commented on 8 Sep 2017
看了一半了,不过概念性的东西实在太多了。 |
brickspert commented on 8 Sep 2017
@ranjin 从我接触react到现在,也有快一年了吧。。。慢慢来,你先学会用别人搭好的现成的框架。熟悉怎么用之后,再来看怎么搭框架。 |
ranjin commented on 8 Sep 2017
嗯嗯。现在就是在看您这整个框架的。然后再慢慢来学习一些知识点的。 |
brickspert commented on 8 Sep 2017
@ranjin JSX |
yeliping commented on 8 Sep 2017
嘿嘿,看了博主文章自己弄了一个,删了一些跟我项目不是很必要的东西,自己改了一点,不过总体还是挺好的。谢谢博主啦。redux我还是去补补,因为之前没怎么接触过。以前一直用angular1.x和vue、jq做项目 |
ranjin commented on 8 Sep 2017
@yeliping 我也感觉redux好绕啊。 |
brickspert commented on 8 Sep 2017
@ranjin 是的,我最开始也不理解。 先学会用,用着用着就懂原理了。~你要明白, |
Ccheng2729111 commented on 13 Sep 2017
写的真的很不错,花了几个小时跟着走了一遍。以前项目都是脚手架create-react-app直接搭的。 |
Ccheng2729111 commented on 13 Sep 2017
不过感觉react-redux那块还可以详尽一点,多创建一个container,纯显示组件就放component里就行。逻辑相关的放container。 这样相信新手就可以少走弯路了:》 |
brickspert commented on 13 Sep 2017
@Ccheng2729111 确实是,redux如果没用过,很难一下就讲清楚的。当时写的时候也考虑了很久~~还是没太讲明白。。。 我现在在准备写一篇从零开发一个redux。相信新手看了会豁然开朗 嘿嘿。 |
brickspert added the react label on 15 Sep 2017
AlenWang commented on 15 Sep 2017
本来是想看一下react入门,忽然最后关注点在webpack配置上。然而我们项目是vue2+webpack,看了之后对webpack配置理解更深刻了些,写的很赞了! |
brickspert commented on 15 Sep 2017
@AlenWang 谢谢认可。 |
brickspert commented on 17 Sep 2017
加入 babel-plugin-transform-runtime 和 babel-polyfill
参考地址:
|
brickspert commented on 17 Sep 2017
集成PostCSS官方文档看这里 Q: 这是啥?为什么要用它? 他有很多很多的插件,我们举几个例子~ Autoprefixer这个插件,可以自动给css属性加浏览器前缀。 /*编译前*/ .container{display: flex; } /*编译后*/ .container{display: -webkit-box;display: -webkit-flex;display: -ms-flexbox;display: flex; } postcss-cssnext 允许你使用未来的 CSS 特性(包括 autoprefixer) 当然,它有很多很多的插件可以用,你可以去官网详细了解。我们今天只用 npm install --save-dev postcss-loader npm install --save-dev postcss-cssnext 修改 webpack.dev.config.js rules: [{test: /\.(css|scss)$/,use: ["style-loader", "css-loader", "postcss-loader"]}] webpack.config.js rules: [{test: /\.css$/,use: ExtractTextPlugin.extract({fallback: "style-loader",use: ["css-loader", "postcss-loader"]})}] 根目录增加 touch postcss.config.js
module.exports = {plugins: {'postcss-cssnext': {}} }; 现在你运行代码,然后写个css,去浏览器审查元素,看看,属性是不是生成了浏览器前缀? |
alexguo88 commented on 19 Sep 2017
万分感谢,学习框架,显得弄清楚构建工具的使用,以前一直迷迷糊糊的,按你的步骤一步一步作下来,清晰多了,很好的文章!!! |
brickspert commented on 19 Sep 2017
@alexguo88 感谢你的认可。谢谢~~以后会有更多好文的、 |
ZHENGGEGE commented on 19 Sep 2017
很细致!一直用到webpack,却没有研究过,文章很棒 |
zhouxinghui commented on 20 Sep 2017 •
edited
不开心 为什么部署到tomcat中报错误,我把dist文件放到tomcat 中 找不到css文件,js文件,文件明明都有,请问是为什么啊 @brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui 你用的一级域名还是二级域名? |
zhouxinghui commented on 20 Sep 2017
没有用域名,我是说直接部署在本地的tomcat中运行一下,老板还没叫我部署到域名服务器上 @brickspert |
brickspert commented on 20 Sep 2017 •
edited
@zhouxinghui 我意思是 你部署到tomcat后,使用" http://localhost:80/index.html " 这种域名访问的?还是 " http://localhost:80/xxx/index.html " 这种域名访问的? 第二种配置确实访问不到静态文件的。如果你非要用第二种域名访问,要修改 |
zhouxinghui commented on 20 Sep 2017 •
edited
我是用第二种,那怎么用第一种呢 ,不想修改那么多配置@brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui tomcalt配置域名 http://localhost:80 直接指向xxx目录就可以了~~你现在肯定是指向xxx目录再外面的一层。 |
zhouxinghui commented on 20 Sep 2017 •
edited
我在tomcat 中的服务器配置中的标签下加了这段 |
brickspert commented on 20 Sep 2017
@zhouxinghui 差不多,我看 |
zhouxinghui commented on 20 Sep 2017
遇到一个问题 在tomcat中部署运行 重复刷新页面会报错误 只有主页重复刷新不报错误,其它页面都会报错误。 @brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui 这是正常的,你要配置tomcat,让所有的页面请求都返回 除了静态文件和api请求哦~ |
zhouxinghui commented on 20 Sep 2017
这个怎么配啊 @brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui 给你个关键字 “tomcat配置单页面应用”,你去查下吧。tomcat我没怎么用过唉~ |
zhouxinghui commented on 20 Sep 2017
我去查了 我没有找到 不知道是不是我查找的方法不对 还是没有 @brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui 你看看这个吧 这里 他这里有apache和nginx的配置(大概意思可以参考,别原模原样复制哦)。 总的思想就是,所有页面请求,重定向到 |
zhouxinghui commented on 20 Sep 2017
我是在Windows下,没有他说的那个文件啊 tomcat我的是直接解压用的 @brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui ant-design/ant-design#2226 |
zhouxinghui commented on 20 Sep 2017 •
edited
在 tomcat 上面简单的做法,在 web.xml 中加入 |
zhouxinghui commented on 20 Sep 2017
不过这样做还是有一个错误 那就是刷新页面的时候 还是会显示找不到页面 但是绑定了主页 所以主页会一直显示~ @brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui 理解不了你的意思了~~~ 是都返回主页的,但是js会控制显示的页面的呢。。 怎么你的不行哩? |
zhouxinghui commented on 20 Sep 2017
不知道啊 楼主你在tomcat中试一试 估计也是一样的 要不我把配好的文件发给你 你看看 我用的是你github上的源码 @brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui 我晚上下个tomcat 试试。没咋用过。 |
zhouxinghui commented on 20 Sep 2017
嗯嗯 好的 那就麻烦你了 @brickspert |
brickspert commented on 20 Sep 2017
@zhouxinghui
亲测可用。 |
zhouxinghui commented on 21 Sep 2017
Chrome浏览器 按F12 可以看到错误 不是页面上报错误 进入开发模式 刷新页面会报404 @brickspert |
brickspert commented on 21 Sep 2017
@zhouxinghui 截个图发上来看看~ |
zhouxinghui commented on 21 Sep 2017 •
edited
|
brickspert commented on 21 Sep 2017
@zhouxinghui 我用我的方法测试了,没问题的。应该是你404页面配置的有问题。你按照我的来配应该就可以了、 |
zhouxinghui commented on 21 Sep 2017
我们的目录结构不一样啊 我把你的源码 dist文件夹拷贝到 Tomcat服务器中的webapps文件夹目录下 静态代码发布到Tomcat都是放在这个目录下的 @brickspert |
zhouxinghui commented on 21 Sep 2017
要是在生产环境 要怎么部署啊 @brickspert 上面你介绍的时候说拷贝dist文件夹 到服务器 我觉得不够清楚@brickspert |
brickspert commented on 21 Sep 2017
@zhouxinghui
|
zhouxinghui commented on 21 Sep 2017
我按你的那个配了 还是这样报错 @brickspert |
brickspert commented on 21 Sep 2017
@zhouxinghui 这个我真的不知道了唉。我这边确实不报错的。tomcat文档看看吧,肯定是tomcat配置的问题~~。~~ |
zhouxinghui commented on 21 Sep 2017
好吧 那这个项目怎么和后端的连接起来啊 @brickspert |
Pegggy commented on 22 Sep 2017
redux 教程那里, Counter 组件我照博主的代码打出错啦。 class Counter extends Component{render(){return(<div><div>显示当前计数为{this.props.counter}</div> //这里 props 应该就到 counter,不然不显示数字<button onClick = {()=>this.props.increment()}>自增</button><button onClick = {()=>this.props.decrement()}>自减</button><button onClick = {()=>this.props.reset()}>重置</button></div>)} }const mapStateToProps = (state) =>{return {counter: state.count,//这里应该是 state.count 不是 counter,不然编译完会报错} } |
brickspert commented on 22 Sep 2017
@Pegggy 亲,应该是你搞错了吧,亲。 看这里,我们在这里定义的是
|
yichonglai commented on 24 Sep 2017
vendor文件没经过babel处理??? |
brickspert commented on 25 Sep 2017
@yichonglai 我是这样理解的。babel只处理src文件夹里面的代码(我们配置的),用 |
yichonglai commented on 25 Sep 2017
\node_modules\webpack-dev-server\client |
brickspert commented on 25 Sep 2017
@yichonglai 不应该啊,webpack-dev-server不会打包进vendor的呀~~ 截个图看看。 |
yichonglai commented on 25 Sep 2017
|
yichonglai commented on 25 Sep 2017
按理不会进vendor |
brickspert commented on 25 Sep 2017
@yichonglai 等我研究下 然后给你回复哦~ |
vonxq referenced this issue in vonxq/vonxq.github.io on 26 Sep 2017
Open
react #1
brickspert commented on 26 Sep 2017 •
edited
redux 模块热替换配置今天突然发现,当修改reducer代码的时候,页面会整个刷新,而不是局部刷新唉。 这不行,就去查了webpack文档,果然是要配置的。看这里 代码修改起来也简单,增加一段监听reducers变化,并替换的代码。
if (module.hot) {module.hot.accept("./reducers", () => {const nextCombineReducers = require("./reducers").default;store.replaceReducer(nextCombineReducers);}); } 哦了~ |
xinkuan-jack commented on 28 Sep 2017
无法兼容ie,好心塞 |
brickspert commented on 28 Sep 2017
@xinkuan-jack 这里我写了这个框架如何兼容ie8的~~ 看这里 #5 |
xinkuan-jack commented on 28 Sep 2017
@brickspert 不考虑ie8了,ie9+能运行就ok,问题还是 @yichonglai 显示的那个问题,转码规则制定了,打包后文件还是es6 |
brickspert commented on 28 Sep 2017
@xinkuan-jack 你是说开发(npm start)的时候兼容ie9 还是 生产坏境(npm run build)之后兼容ie9呢? |
brickspert commented on 28 Sep 2017
@xinkuan-jack 我测试了,打包之后是兼容ie9+的,你开发的时候不要用ie9开发啊~ |
brickspert commented on 13 Oct 2017
@tingyuxuan2302 报错说的是,你配置文件写的不对,你配置一个 |
sanshuiwang commented on 18 Oct 2017
笔者,留个QQ或者微信,有问题好请教嘛! |
sanshuiwang commented on 19 Oct 2017
我想抽取scss还是像抽取css一样吗? |
brickspert commented on 19 Oct 2017
@sanshuiwang 没理解你的意思。 scss和css是一样的哦。 |
firstsmarts commented on 30 Oct 2017
谢谢分享 获益良多 |
zhangtianxiao commented on 30 Oct 2017
辛苦了, |
xuezhenxiang commented on 3 Nov 2017
谢谢分享! |
xintianyou commented on 8 Nov 2017
谢谢提主的分享,相当精彩! |
xintianyou commented on 8 Nov 2017
上面的QQ群加不进 |
brickspert commented on 8 Nov 2017
@xintianyou 可以加了 |
xintianyou commented on 8 Nov 2017
@brickspert 谢谢 |
JaydenLD commented on 8 Nov 2017
就是有个地方不知道怎么改哪里,就是 redux: path.join(__dirname, 'src/redux')注释掉以后,我点击counter就报错了 |
brickspert commented on 9 Nov 2017 •
edited
@JaydenLD 可以把报错信息贴出来。是不是你有文件引用了这样的路径 |
JaydenLD commented on 9 Nov 2017
我点击Counter以后 |
brickspert commented on 9 Nov 2017
@JaydenLD
|
JaydenLD commented on 9 Nov 2017
这里改了就报错 |
brickspert commented on 9 Nov 2017
@JaydenLD 哈~这里你写错了,应该这么写的,这里。 |
JaydenLD commented on 9 Nov 2017
|
brickspert commented on 9 Nov 2017
@JaydenLD 你把我源码下载下来,对比一下吧~ 我这么看也看不出的 |
JaydenLD commented on 9 Nov 2017
好的,还是谢谢啦 |
FrankHuPerficient commented on 10 Nov 2017
博主厉害了。写得很清晰。谢谢分享。 |
lm5645 commented on 10 Nov 2017
打包优化的命令是错的:现在npm run bundle试试,是不是之前的都清空了。当然我们之前的api文件夹也被清空了,不过没关系哦~本来就是测试用的。build |
JaydenLD commented on 10 Nov 2017
昨天下午已经按照这个重新来了一遍,是因为当时我install的依赖没有下载进去,json文件里没有,所以路径改了也会报错 |
brickspert commented on 10 Nov 2017
@lm5645 谢谢。已经改正了。thank you~ |
brickspert commented on 10 Nov 2017 •
edited
@JaydenLD 可以用了就好~祝你好运 |
git-issue commented on 10 Nov 2017
写得很不错,谢谢楼主分享 |
hezhii referenced this issue in brickspert/react-family on 14 Nov 2017
Open
使用 babel-preset-env #1
nanxiaodi commented on 15 Nov 2017
打包之后,用webstorm打开页面,发现报错, |
robinLiu1989 commented on 15 Nov 2017
@nanxiaodi,我遇到了和你同样的问题 |
brickspert commented on 16 Nov 2017
@nanxiaodi @robinLiu1989
|
nanxiaodi commented on 16 Nov 2017
用服务器发布就好了,我找了一下原因,第一是,出口配置不弄成绝对路径,publice:'./'变成相对路径就可以访问资源了,然后是子页面的路由设置,是BrowserRouter好像必须要服务器支持,改成hashrouter就可以在本地运行了 |
robinLiu1989 commented on 16 Nov 2017
@brickspert 在本地开了一个服务器,确实可以,谢谢楼主~ |
brickspert closed this on 16 Nov 2017
ZGahou commented on 16 Nov 2017
|
brickspert commented on 16 Nov 2017
@ZGahou 你肯定知道,我们这是单页面应用。我们只有一个文件Index.html~ |
ZGahou commented on 16 Nov 2017
browserRouter会重新请求服务器,webpack-dev-server怎么配置能让404返回index.html |
brickspert commented on 16 Nov 2017
@ZGahou 原来你在开发模式呀,其实你往后看,后面就有写到开发模式如何处理的。 |
ZGahou commented on 16 Nov 2017
之前没发现这个的用处,没加上,现在可以了,多谢楼主 |
brickspert commented on 16 Nov 2017
@ZGahou 这样最好了,完全理解这个字段了。下次碰到肯定记住了。嘿嘿。碰到问题,解决问题后才能记住。 |
ZGahou commented on 16 Nov 2017
是啊,现在记住了devServer里有这么个配置可以起到这个作用 |
FrankHuPerficient commented on 16 Nov 2017
@TrustTheBoy 将运行命令写在package.json中就可以了 |
brickspert reopened this on 16 Nov 2017
brickspert commented on 17 Nov 2017
@TrustTheBoy 你看报错信息, |
TrustTheBoy commented on 17 Nov 2017 •
edited
@brickspert 您好,感谢你的帮助,我的Router确实是一个子节点,我也对照了你的源码 |
brickspert commented on 17 Nov 2017
@TrustTheBoy |
brickspert commented on 17 Nov 2017
@TrustTheBoy 我看着也没啥问题。。尴尬。你下载我的源码对比下吧。看不出来哪里错了~~ 如果最后还不行,晚上我 可以帮你调试下。 |
TrustTheBoy commented on 17 Nov 2017 •
edited
@brickspert 是不是和react && react-dom的版本有关呢?我用的全是新版本 |
brickspert commented on 17 Nov 2017
@TrustTheBoy 应该不是的~~不过你可以尝试的。 |
TrustTheBoy commented on 17 Nov 2017
@brickspert 您好,想问下,如果按" http://localhost:80/xxx/index.html " 这种域名访问的,publicPath这里需要如何配置呢?还有路由需要怎么改动呢? |
brickspert commented on 17 Nov 2017
@TrustTheBoy
|
brickspert commented on 17 Nov 2017
@TrustTheBoy hello~
|
brickspert commented on 20 Nov 2017
@TrustTheBoy 我意思是这个路径下的所有404,定位到index.html。。。不是说服务器上所有的。。 |
brickspert commented on 21 Nov 2017 •
edited
模拟AJAX数据之Mock.js每个改进都是为了解决问题。 现在我在开发中碰到了问题,我先描述下问题: 我们现在做前后端完全分离的应用,前端写前端的,后端写后端的,他们通过API接口连接。 前端同学心理路程:"后端同学接口写的好慢,我都没法调试了。" 是不是有这个问题呢?一般我们怎么解决? 第一种:自己这边随便造点数据,等后端接口写好了之后,再小修改,再调试。 第二种:想想我们之前获得用户信息的 并且,后端接口一般都不带 好了,下面介绍下今天的主角Mock.js。 他会做一件事情:拦截AJAX请求,返回需要的数据! 我们写AJAX请求的时候,正常写,Mock.js会自动拦截的。 Mock.js提供各种随机生成数据。具体可以去官网看~ 下面我们就在项目中集成咯:
现在我们运行 到这里还没完,我们还要配置:只有在开发坏境下,才引入 跟着我做: 先给
然后修改
这样,就只会在 哦了,到这里就结束了~回头缕下: 我们定义了mock,在index.js引入。 mock的工作就是,拦截AJAX请求,返回模拟数据。 参考文章: http://www.jianshu.com/p/dd23a6547114 https://segmentfault.com/a/1190000005793320 |
xiaofuyesnew commented on 24 Nov 2017 •
edited
打算把koa和这个脚手架放在一起,做一个全栈的脚手架,koa处理后端逻辑为前端提供REST API,前端处理交互逻辑和页面,另外的话,想一想其实ORM也可以放进来。数据库用MongoDB,用js实现完全的全栈。 |
TrustTheBoy commented on 27 Nov 2017
现在的问题是,this.props拿到的全是{},里面啥都没有Link.to传的参数也传不过去 |
brickspert commented on 27 Nov 2017
@TrustTheBoy 在什么地方拿不到?~截图看看。 |
TrustTheBoy commented on 27 Nov 2017 •
edited
@brickspert 能否发个QQ或者什么联系方式呢?我的QQ:603049583 |
TrustTheBoy commented on 27 Nov 2017 •
edited
比如我用Link <Link to={{ pathname: `/details/${item.id}`, query: { foo: 'bar', boo: 'boz' }}} key={i}><ListItem primaryText={item.name} rightIcon={<HardwareKeyboardBackspace />} style={{ borderBottomWidth:0.1,borderBottomColor:'#e5e5e5',borderBottomStyle:'solid',backgroundColor:'#fff' }} /> </Link> 然后details这个页面this.props获取也是{} |
HuYuee commented on 28 Nov 2017
写的很详细!? |
brickspert commented on 28 Nov 2017
@TrustTheBoy 我加你了。 |
purpletastes commented on 29 Nov 2017
|
brickspert commented on 29 Nov 2017 •
edited
@dushengling 你往下看。下面一点点我就写了这个问题。 |
purpletastes commented on 30 Nov 2017
|
purpletastes commented on 30 Nov 2017
brickspert commented on 30 Nov 2017
@purpletastes 不是进度条,是百分比进度~ 第二个这个,肯定是你代码写错了。。。。你仔细看看哪里没写对。 |
purpletastes commented on 1 Dec 2017
@brickspert 谢谢,还是没有找到原因。能不能加一下你,有很多问题想请教一下 |
brickspert commented on 1 Dec 2017
@purpletastes 你告诉我你QQ ,我拉你进群。 |
robinLiu1989 commented on 4 Dec 2017
@brickspert 这样为什么不行? |
brickspert deleted a comment from purpletastes on 4 Dec 2017
brickspert commented on 4 Dec 2017
@robinLiu1989 你是想用这种域名
总结来说,js引用,htmlwebpackplugin会自动给你插入的,不用你自己去写的。 |
gejialun8888 commented on 7 Dec 2017 •
edited
请教一下上面props怎么能够有下面props这些参数啊,不知道react-router4怎么写 |
brickspert commented on 7 Dec 2017 •
edited
@gejialun8888 用 |
gejialun8888 commented on 8 Dec 2017
谢谢啊 @brickspert ,但是在项目不知道怎么写最合适,还是相关代码或者项目案例提供一下给做个参考呢 |
brickspert commented on 8 Dec 2017
@gejialun8888
|
gejialun8888 commented on 8 Dec 2017
@brickspert 太感谢了,可以了,升级的成本太高了,方便加个QQ:516736959 |
brickspert deleted a comment from JackZs on 8 Dec 2017
brickspert deleted a comment from JackZs on 8 Dec 2017
kkkkzero00 commented on 12 Dec 2017
请问一下公共的webpack文件抽离出来后,执行开发模式或者生产模式的时候指令 指向的文件会发生变化吗?比如 "dev": "webpack-dev-server --config webpack.dev.config.js --color --progress",里面到底是指向 webpack.dev.config.js还是 webpack.dev.common.js |
brickspert commented on 12 Dec 2017 •
edited
@kkkkzero00 不用改的哦。还是老样子。 |
shenhailong commented on 13 Dec 2017
@brickspert 楼主太棒了!!!对于我这种不上不下的学习者来说很实用。跟着写了一遍,webpack的也基本走通了,希望能多出更多的学习教程 |
qianlanse commented on 13 Dec 2017
@brickspert 在刷新那一节,修改后为啥我浏览器没有刷新呢倒是编译文件了,164295410求加进群 |
brickspert commented on 13 Dec 2017
@qianlanse 代码你再对比下。肯定是代码写错了哦。尤其是 |
brickspert commented on 13 Dec 2017
@shenhailong 谢谢。很开心能帮到你~ |
brickspert commented on 13 Dec 2017
使用 CSS Modules关于什么是 可以去看阮一峰的文章CSS Modules 用法教程 修改以下几个地方:
enjoy it! |
robinLiu1989 commented on 14 Dec 2017
@brickspert 这种单页面应用,分享链接时,比如www.test.com/detail。别人需要直接访问www.test.com/detail这个地址,该这么弄,看前文是链接到index,有没有办法直接跳到指定页面呢? |
brickspert commented on 14 Dec 2017
@robinLiu1989 就是直接访问 |
robinLiu1989 commented on 14 Dec 2017
@brickspert ,举个例子,我要访问http://brofe.natapp1.cc/articleDetail,目前我只能先进入http://brofe.natapp1.cc/,然后在点击页面进入到http://brofe.natapp1.cc/articleDetail,如果直接访问http://brofe.natapp1.cc/articleDetail就不行 |
brickspert commented on 14 Dec 2017
@robinLiu1989 那是你服务器这边配置的不对哦。 |
nixiaowei commented on 14 Dec 2017
不得不说,这篇文章全是干货~~~ 给楼主点个赞~~~ |
robinLiu1989 commented on 14 Dec 2017
@brickspert 可以了,谢谢 |
brickspert commented on 14 Dec 2017
@nixiaowei 谢谢 |
zhh877644371 commented on 14 Dec 2017
请问一下,最后一个“使用 CSS Modules模块”中,不需要安装什么依赖吗,我之前都没问题,最后按照步骤来修改文件,npm start报错了,感觉像是依赖的问题 @brickspert 楼主的分享很棒,能不能把我也拉到群里一起学习,我的qq是877644371 |
brickspert commented on 14 Dec 2017
不用安装依赖的哦~
这句就是开启css modules模式的。 另外,我看你报错信息说是 |
zhh877644371 commented on 14 Dec 2017
是图片没找到...我用的是自己的图片,jpg名字不对,太不细心了...感谢楼主的分享~ |
HeavenSky commented on 15 Dec 2017 •
edited
首先谢谢砖家大大的分享,不过我提一点点新人的建议,希望相互学习和相互进步。
const createComponent = (modFn) => props => (<Bundle load={modFn}>{(WaitingComponent) => WaitingComponent ? <WaitingComponent {...props}/> : <Loading {...props}/>}</Bundle> ); 说实话,之前都叫component的时候我理解了好久好久,建议命名更语义化一点component太通用,容易误解,其实第一个小写的component是一个回调函数,第二个首字母大写的Component才是加载完成的组件.另外因为没有将props给传递给bundle-load的组件,所以这些组件无法获取location,history等信息 因为我也是最近几个月学习react(十一国庆假开始学的),最近一个半月开始准备自己配webpack(自用,公司用的gulp,没法参考),按照你的项目代码,自己也写了react一个最新的支持ie9,一个支持到ie8的,不过我因为想用ant design所以配置上有很多不同,也弃用了redux,(redux是好东西但是很多时候可以不用) |
HeavenSky commented on 15 Dec 2017
|
brickspert commented on 15 Dec 2017
@HeavenSky 感谢您的建议,非常感谢。
|
HeavenSky commented on 15 Dec 2017
我对应写了两个项目
|
zyt-cloud commented on 18 Dec 2017
为啥polyfill不单独抽出一个文件来 |
brickspert commented on 18 Dec 2017 •
edited
使用 json-server 代替 Mock.jsjson-server和
我们用
let Mock = require('mockjs');var Random = Mock.Random;module.exports = function () {var data = {};data.user = {'name': Random.cname(),'intro': Random.word(20)};return data; };
devServer: {...proxy: {"/api/*": "http://localhost:8090/$1"}} 哦了,你可以 问题: |
apawn commented on 19 Dec 2017
博主写的很好很详细, 给了我很大帮助 thank you |
ZGahou commented on 20 Dec 2017
|
brickspert commented on 20 Dec 2017
@ZGahou 这个确实是个问题。
|
ZGahou commented on 20 Dec 2017
谢谢楼主,那旧的版本有这个bug吗,我现在用的版本是3.0.0 |
brickspert commented on 20 Dec 2017
@ZGahou 据我上次测试,旧版本也没用了~~ 下个版本这个bug就修复了。得等等了。= =! |
ZGahou commented on 20 Dec 2017
好的,谢谢楼主 |
kkkkzero00 commented on 20 Dec 2017
|
brickspert commented on 20 Dec 2017
@xinkuan-jack #5 |
BackToHappyBear commented on 26 Dec 2017
楼主,我想在一个action后 获取数据 再执行另一个action,好像在 afterSuccess 中执行 并不可以? |
brickspert commented on 26 Dec 2017
@BackToHappyBear 可以的。
|
beeant0512 added a commit to beeant0512/react-family-ie8 that referenced this issueon 26 Dec 2017
不支持IE8
…
44a2aa6
hwanpenn commented on 4 Jan
写得真的太棒了 我要申请加入组织 1472456186 |
lxh3811958 commented on 4 Jan
楼主,我也要申请加入组织,2467057727 |
fanpengfei510 commented on 5 Jan
写的太好了,很详细也很实用,申请进组织,可以和大家多交流。598796448 |
answer33 commented on 5 Jan
感谢分享,想加入群,一切探讨,谢谢啦。351557265 |
cdLVV commented on 8 Jan
你好,谢谢分享,楼主我也想加群,谢谢啦. 463799002 |
Caixiaozhi commented 28 days ago
求入群!1006219023! |
brickspert commented 28 days ago
@cdLVV @Caixiaozhi 群号:572071150 |
ZGahou commented 28 days ago
楼主你好,怎么加svg的配置 |
brickspert commented 28 days ago
@ZGahou
|
cokecole commented 27 days ago
楼主 热加载那儿按上面那样写的 但是不起作用但是每次保存都会更新显示 webpack: Compiled successfully. |
brickspert commented 27 days ago
@cokecole 572071150 |
wj15510151110 commented 27 days ago
396553000 |
ghost2113 commented 26 days ago •
edited
|
brickspert commented 26 days ago
@ghost2113 用了路由跳转之后,就不能用 |
huangdeyao commented 26 days ago
怎么集成蚂蚁的antd? |
wangwenfan commented 21 days ago
按照你的方式搭建到 devServer: {contentBase: path.join(__dirname, './dist')} 但目录结构是: 根据这句 我把 |
brickspert commented 21 days ago
@wangwenfan 程序启动起来,会打包好文件放到dist文件夹的,打包的文件放在内存中,是无法看到的。 看看你的 无法访问看看报错信息是什么? |
mengwuhen commented 15 days ago
你好,我想问一下 上边的教程 我自己操作了一遍,想结合ant-design 搭建一个系统的静态页面 ,但是发现antd的样式没有加载进来。请问这种情况下 webpack该如何配置,谢谢 |
brickspert commented 15 days ago
@mengwuhen 不用特殊配置呀,就安装官网推荐的就可以哦。https://ant.design/docs/react/introduce-cn#%E6%8C%89%E9%9C%80%E5%8A%A0%E8%BD%BD |
li2290 commented 12 days ago
大神请问一下源代码html文件中的内联样式能通过什么插件打包进去吗 |
brickspert commented 12 days ago
@li2290 不是很懂你的意思。 |
mingyun referenced this issue in mingyun/mingyun.github.io 8 days ago
Open
网站收集 #92
em14Vito commented 8 days ago
@brickspert 楼主好,按照你的步骤走到react那儿,打包的时候就报错了:
|
brickspert commented 7 days ago
@em14Vito 你好,应该是你的配置文件没写对。可以把 webpack配置文件贴出来看看。 |
em14Vito commented 7 days ago •
edited
@brickspert
webpack.dev.config
package.jason
其实都是跟你上面写的是一样 : ( |
CJHHappy commented 7 days ago
你这篇文章确实写得很好,很细致,最主要的就是没有用太多的官方术语去表达知识,而是用了通俗易懂的语言去描述,这里大家就肯定能听得懂,也知道什么东西是干什么事的。也能体现出来你自己的理解。通俗易懂,不错。建议像这类的文章,有精力你应该多写几篇。 |
brickspert commented 7 days ago
@em14Vito 亲,你看下你的 |
brickspert commented 7 days ago
@CJHHappy 这段时间太忙了,等过完年了,肯定会继续写的。 |
em14Vito commented 7 days ago
@brickspert 是在下眼瞎了,谢啦 ? |
JashonWang commented 6 days ago
写得真不错 |
brickspert commented 19 hours ago
问题修复1. react热模块加载无效举例:在首页中,当我们计数加上去,然后修改代码,计数又恢复成0了。也就是热模块加载的时候,重置了 如果我们不使用 解决问题参考这里:https://github.com/gaearon/react-hot-loader/tree/next#code-splitting 解决步骤:
import {hot} from 'react-hot-loader'; ... export default hot(module)(Home); 其他模块如果需要,可以自己同理修改哦。 |
ilovekerry commented 2 hours ago
connect接收两个参数,一个mapStateToProps,就是把redux的state,转为组件的Props,还有一个参数是mapDispatchToprops, 先来安装react-redux npm install --save react-redux src/pages/Counter/Counter.js import React, {Component} from 'react'; |
brickspert commented an hour ago
@ilovekerry 没写错的,你注意下“文件路径优化”这一节。要加路径别名配置的哦 |
react 环境 全家桶相关推荐
- 2023新春版:看这篇大宝典就够了!从零搭建React项目全家桶
React是近年来前端开发领域非常热门的技术框架,其背景是Facebook团队的技术支持,在全球的前端开发市场上占有率很高.结合React丰富的社区资源,可以让项目开发如虎添翼.虽然React的学习门 ...
- 视频教程-19年全新React教程全家桶实战redux+antd+dva+Hooks前端js视频-ReactJS
19年全新React教程全家桶实战redux+antd+dva+Hooks前端js视频 7年的开发架构经验,曾就职于国内一线互联网公司,开发工程师,现在是某创业公司技术负责人, 擅长语言有node/j ...
- react安装_超全面详细一条龙教程!从零搭建React项目全家桶(上篇)
React是近几年来前端项目开发非常火的一个框架,其背景是Facebook团队的技术支持,市场占有率也很高.很多初学者纠结一开始是学react还是vue.个人觉得,有时间的话,最好两个都掌握一下.从学 ...
- 【React自制全家桶】一、Webstrom+React+Ant Design+echarts搭建react项目
前言 一.React是Facebook推出的一个前端框架,之前被用于著名的社交媒体Instagram中,后来由于取得了不错的反响,于是Facebook决定将其开源.出身名门的React也不负众望,成功 ...
- Python环境全家桶(永久使用)
一.Python安装 本人一直是Java爱好者,第一次接触python,周围做爬虫或者信息AI开发的小伙伴都说Python语言简单,所以多学一点是没有坏处的,接下来是一个完全不懂Python的小白对安 ...
- 小邵教你玩转Typescript、ts版React全家桶脚手架
前言:大家好,我叫邵威儒,大家都喜欢喊我小邵,学的金融专业却凭借兴趣爱好入了程序猿的坑,从大学买的第一本vb和自学vb,我就与编程结下不解之缘,随后自学易语言写游戏辅助.交易软件,至今进入了前端领域, ...
- 从零搭建React全家桶框架教程
从零搭建React全家桶框架教程 源码地址:https://github.com/brickspert/react-family 欢迎star 提问反馈:blog 原文地址:https://githu ...
- react全家桶从0到1(react-router4、redux、redux-saga)
本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redux-saga的核心配置会加以讲解, ...
- 使用react全家桶制作博客后台管理系统
前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基于react全家桶(React.React-r ...
最新文章
- 用apxs来扩增apache的模块
- chapter2.3、react高阶组件,装饰器
- FFMPEG结构体分析之AVFormatContext
- [原创]java获取word里面的文本
- 论坛中的验证码的作用
- 【微波】【1】色散关系式与 TEM导波、TE导波、TM导波、混合波区别和特性
- pr 无法启动因为计算机丢失,pramtlib.dll_“PR打不开,因为计算机丢失TimeWarpFilter.dll”是怎么回事?怎么办啊?_prccamtlib.dll...
- 【比特率和波特率】bit rate VS baud rate
- 《货币简史》书中的精髓:货币产生的起源是什么?货币又是如何发展起来的?
- 随机无梯度Frank-Wolfe方法的统一分析
- java编程计算圆球的体积_已知圆球体积为4/3πr³,试编写一个程序,输入圆球半径,经过计算输出圆球的体积.用JAVA编写的...明天(3月11号)要用....
- 早上还在改 Bug,晚上就被裁了
- 阿里云的域名和ip绑定
- SDN网络下有哪些SDN交换机选择?
- 计蒜客T1005输出字符三角形
- 数据库逻辑设计之 三大范式 及 反范式化 优缺点
- mysql存储过程_mysql存储过程的写法
- org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actua
- iOS提交版本时苹果官方审核拒绝原因详解
- windows 下 c++ 快速截屏
热门文章
- Bayes 分类器随笔
- dx绘制2d图像_Direct2D教程II——绘制基本图形和线型(StrokeStyle)的设置详解
- 国产电容式触控IC的工作原理及应用
- 访问控制/越权漏洞 -- 学习笔记
- 中南大学计算机导师名单,中南大学信息学院导师一览表.pdf
- win10解决一卡一卡
- activemq 限制访问ip、修改web访问密码、队列连接密码
- 基于JS+HTML实现的纯前端天气预报实时查询系统
- 最优化方法:牛顿迭代法和拟牛顿迭代法
- 密码学中的PRNG(pseudorandom number generator)及PRF(Pseudo-Random Functions)