本文记录了在开发
react-cnode
时,所使用的react项目模板react-starter。create-react-app
是非常优秀的官方脚手架,已经提供了丰富的功能,该模板是基于create-react-app
创建的项目eject后,在不影响原有功能的前提下,根据个人的需要进行了一些定制。
目录
使用webpack2
使用webpack v2替换原来的webpack v1,webpack v1和v2的差异不在这里赘述了,可以参考官方文档Migrating from v1 to v2,也有相应的中文文档从 v1 迁移到 v2。
需要注意的是,webpack2内建支持ES2015模块,所以设置babel中es2015配置的modules为false,同时这也是支持react组件热更新所必要的配置,修改babel配置为:
"babel": {
"presets": [
[
"es2015",
{
"modules": false
}
],
"stage-0",
"react"
]
}
这里没有用原来的babel-preset-react-app
,而是用了es2015
+ stage-0
+ react
,因为babel-preset-react-app
不支持一些实验性的语言特性,所以使用时自行斟酌。
多入口
每次新建项目都进行一次create-react-app,尤其有时候可能只是一个简单的页面,是比较繁琐的,因为create-react-app只支持一个文件入口,所以支持多入口是有必要。
要支持多入口,只需要对config/paths.js
进行一些改动。
读取npm命令时的参数:
let appname = process.argv.find(arg => arg.indexOf('app=') === 0);
appname = appname ? appname.split('=')[1] : '';
然后修改一下输出路径:
appBuild: resolveApp(`build/${appname}`),
appPublic: resolveApp(`public/${appname}`),
appHtml: resolveApp(`public/${appname}/index.html`),
appIndexJs: resolveApp(`src/${appname}/index.js`),
就这么简单,┑( ̄Д  ̄)┍,修改之后兼容之前的项目结构,也就是可以直接在src目录下添加代码文件,要使用多入口,需要分别在src
和public
目录下新建相同名称的目录,比如:
- public
- react
- react-router
- src
- react
- react-router
然后分别在目录下添加代码文件,具体可以参考react-starter的项目结构。
在npm命令时加入-- app=appname
参数,示例如下:
npm start -- app=appname
npm run build -- app=appname
serve -s build/appname
分离第三方库
注意:此时需要一个配置文件,我起名为
appconfig.js
,将它固定放在各自项目目录下与index.js
同级,放在其他地方就找不到啦~
增加一个配置文件很简单,首先需要一个fsExistsSync方法判断这个配置文件是否存在,然后在config/paths.js中增加配置文件路径:
appConfigJs: resolveApp(`src/${appname}/appconfig.js`)
接着只需要在webpack配置webpack.config.dev.js和webpack.config.prod.js引入appconfig.js
文件加载配置:
const appConfig = fsExistsSync(paths.appConfigJs) ? require(paths.appConfigJs) : {};
const appConfigEntry = appConfig.entry;
最后再修改webpack.config.prod.js
的entry配置为:
Object.assign({
main: [
require.resolve('./polyfills'),
paths.appIndexJs
]
}, appConfigEntry)
并且在plugins的配置内增加CommonsChunkPlugin
插件:
new webpack.optimize.CommonsChunkPlugin({
names: ['main', 'manifest'].concat(Object.keys(appConfigEntry))
}),
webpack.config.dev.js
的修改类似,这里我固定了应用文件打包后文件名为main.js
。
对于想要打包在一个文件中的库文件,比如想把react
和react-dom
这两个库文件一起打包进react.js
文件中,以及其他打包进vendors.js
中,可以在appconfig.js
中进行以下配置:
module.exports = {
entry: {
react: ['react', 'react-dom'],
vendors: ['rxjs', 'immutable', 'axios', 'react-redux', 'react-router-dom', 'redux', 'redux-observable']
}
};
这是非常有必要的,具体原因可以参考官方对code-splitting-libraries的说明,中文文档代码分离 - Libraries。
支持react组件热更新
这里使用react hot loader 3来支持react组件的热更新。
- 在
webpack.config.dev.js
的entry配置中加入'react-hot-loader/patch'
,注意它需要放在顶部,即:entry: Object.assign({ main: [ 'react-hot-loader/patch', require.resolve('react-dev-utils/webpackHotDevClient'), require.resolve('./polyfills'), paths.appIndexJs ] }, appConfigEntry)
- 在babel-loader的配置plugins中加入
react-hot-loader/babel
,即:{ test: /\.(js|jsx)$/, include: paths.appSrc, loader: 'babel-loader', options: { cacheDirectory: true, plugins: [ 'react-hot-loader/babel' ] } }
<AppContainer/>
是处理模块重新加载以及错误处理的组件。应用程序的根组件应该作为子组件嵌套在AppContainer中。在生产环境中,AppContainer自动禁用,只返回其子组件。具体使用代码如下:
具体可以参考示例import React from 'react'; import ReactDOM from 'react-dom'; import {AppContainer} from 'react-hot-loader'; import App from './App'; import './index.css'; const root = document.getElementById("root"); const render = (Component) => { ReactDOM.render( <AppContainer> <Component /> </AppContainer>, root ); }; render(App); // Hot Module Replacement API if (module.hot) { module.hot.accept('./App', () => { render(App); }); }
react-router
或者示例react
。
react组件按需加载
你可以使用lazy-load-react
来进行组件的按需加载,使用lazy-load-react
提供的方法加载文件,同时也支持热更新! 在本项目模板中已经内置,在其他项目中使用可通过:
npm install lazy-load-react
使用方法:
import lazyme from 'lazy-load-react';
const HomePage = lazyme(() => System.import('./HomePage'));
<Route exact path="/" component={HomePage}/>
具体使用方法可以参考示例react-router App
或者react-cnode App
。
支持alias配置
与配置第三方库文件类似,需要在appconfig.js
中进行配置。
alias的使用方法请参考官方文档resolve.alias。resolve下也可以进行官方文档Resolve中其他配置项的配置。中文文档解析(Resolve)。appconfig.js
配置示例如下:
module.exports = {
entry: {
react: ['react', 'react-dom'],
vendors: ['rxjs', 'immutable', 'axios', 'react-redux', 'react-router-dom', 'redux', 'redux-observable']
}
resolve: {
alias: {
'Containers': path.resolve(__dirname, 'containers/')
}
}
};
这有好处也有坏处,好处是可以简化引入模块是的路径,比如: 原来是
import Page from '../../containers/page';
可以写成
import Page from 'Containers/page';
然而这么做后,编辑器可能无法对路径进行解析,影响比如路径正确性检验、文件移动修改对应文件引用等功能,所以是否使用自行斟酌。
本文对你有帮助?欢迎扫码加入前端学习小组微信群: