├── public
├── favicon.ico
├── manifest.json
└── index.html
├── src
├── static
│ ├── img
│ │ ├── 1.jpg
│ │ ├── 2.jpg
│ │ ├── 3.jpg
│ │ └── reader.png
│ └── svg
│ │ ├── reader.svg
│ │ ├── 1.svg
│ │ ├── 2.svg
│ │ ├── 3.svg
│ │ ├── 4.svg
│ │ └── logo.svg
├── css
│ └── index.css
├── components
│ ├── Search.scss
│ ├── BookDetails.scss
│ ├── BookDetails.js
│ ├── Search.js
│ ├── FilterWrap.js
│ ├── FilterWrap.scss
│ ├── InfoItemList.js
│ ├── Bookstore.scss
│ ├── InfoItemList.scss
│ └── Bookstore.js
├── App.test.js
├── api
│ ├── girl.json
│ ├── Api.js
│ ├── public.json
│ └── boy.json
├── index.js
├── App.css
├── App.js
└── registerServiceWorker.js
├── .gitignore
├── config
├── jest
│ ├── fileTransform.js
│ └── cssTransform.js
├── polyfills.js
├── paths.js
├── env.js
├── webpackDevServer.config.js
├── webpack.config.dev.js
└── webpack.config.prod.js
├── README.md
├── scripts
├── test.js
├── start.js
└── build.js
└── package.json
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infinityX3/reactApp/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/static/img/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infinityX3/reactApp/HEAD/src/static/img/1.jpg
--------------------------------------------------------------------------------
/src/static/img/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infinityX3/reactApp/HEAD/src/static/img/2.jpg
--------------------------------------------------------------------------------
/src/static/img/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infinityX3/reactApp/HEAD/src/static/img/3.jpg
--------------------------------------------------------------------------------
/src/static/img/reader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/infinityX3/reactApp/HEAD/src/static/img/reader.png
--------------------------------------------------------------------------------
/src/css/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | font-size: 16px;
6 | font-family: 'Microsoft Yahei', '微软雅黑', sans-serif;
7 | }
--------------------------------------------------------------------------------
/src/components/Search.scss:
--------------------------------------------------------------------------------
1 | .search {
2 | .nav-bar {
3 | background-color: #e87646 !important;
4 | color: #fff !important;
5 | .am-navbar-title {
6 | color: #fff !important;
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/components/BookDetails.scss:
--------------------------------------------------------------------------------
1 | .BookDetails {
2 | .nav-bar {
3 | background-color: #e87646 !important;
4 | color: #fff !important;
5 | .am-navbar-title {
6 | color: #fff !important;
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea/
3 | .vscode/
4 | node_modules/
5 | dist/
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | test/unit/coverage
10 | test/e2e/reports
11 | selenium-debug.log
12 | export_translation/i18n/
13 | export_translation/i18n_copy/
14 | export_translation/GCRM翻译*/
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/api/girl.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": [{
3 | "imgSrc": "http://wfqqreader.3g.qq.com/cover/490/15313490/t3_15313490.jpg",
4 | "title": "大主宰",
5 | "des": "在破败中崛起,在寂灭中复苏。 沧海成尘,雷电枯竭,那一缕幽雾又一次临近大地,世间的枷锁被打开了,一个全新的世界就此揭开神秘的一角",
6 | "type": "希行 / 古言",
7 | "status": "end",
8 | "id": "1"
9 | }]
10 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import registerServiceWorker from './registerServiceWorker';
5 |
6 | import './css/index.css';
7 | import 'antd-mobile/dist/antd-mobile.css';
8 |
9 | ReactDOM.render(
10 | ,
11 | document.getElementById('root')
12 | );
13 | registerServiceWorker();
14 |
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/en/webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-title {
18 | font-size: 1.5em;
19 | }
20 |
21 | .App-intro {
22 | font-size: large;
23 | }
24 |
25 | .App-intro a {
26 | display: inline-block;
27 | width: 100%;
28 | height: 30px;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from { transform: rotate(0deg); }
33 | to { transform: rotate(360deg); }
34 | }
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # reactApp
2 | A React.js project (仿QQ浏览器小说-书城界面实现)
3 |
4 | > 项目使用creat-react-app构建
5 |
6 | ### 运行截图
7 |
8 |
9 | ### 使用技术
10 | - `React.js` 轻量级的MVVM框架
11 | - `react-router-dom` 前端路由
12 | - `axios` 基于 promise 的 HTTP 库
13 | - `Webpack` 构建工具
14 | - `ant-design-mobile` 基于React.js的UI组件库
15 |
16 | ## Build Setup
17 |
18 | ``` bash
19 | # install dependencies
20 | npm install
21 |
22 | # serve with hot reload at http://localhost:3000
23 | npm start
24 |
25 | # build for application with minification and using the release config.
26 | npm run build
27 |
--------------------------------------------------------------------------------
/src/api/Api.js:
--------------------------------------------------------------------------------
1 | import Axios from 'axios';
2 |
3 | export default {
4 | get (url, params) {
5 | return new Promise((resolve, reject) => {
6 | Axios.get(url, { params: params })
7 | .then(response => {
8 | resolve(response);
9 | })
10 | .catch(err => {
11 | reject(err);
12 | });
13 | });
14 | },
15 | post (url, params) {
16 | return new Promise((resolve, reject) => {
17 | Axios.post(url, params)
18 | .then(response => {
19 | resolve(response);
20 | })
21 | .catch(err => {
22 | reject(err);
23 | });
24 | });
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/scripts/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Do this as the first thing so that any code reading it knows the right env.
4 | process.env.BABEL_ENV = 'test';
5 | process.env.NODE_ENV = 'test';
6 | process.env.PUBLIC_URL = '';
7 |
8 | // Makes the script crash on unhandled rejections instead of silently
9 | // ignoring them. In the future, promise rejections that are not handled will
10 | // terminate the Node.js process with a non-zero exit code.
11 | process.on('unhandledRejection', err => {
12 | throw err;
13 | });
14 |
15 | // Ensure environment variables are read.
16 | require('../config/env');
17 |
18 | const jest = require('jest');
19 | const argv = process.argv.slice(2);
20 |
21 | // Watch unless on CI or in coverage mode
22 | if (!process.env.CI && argv.indexOf('--coverage') < 0) {
23 | argv.push('--watch');
24 | }
25 |
26 |
27 | jest.run(argv);
28 |
--------------------------------------------------------------------------------
/src/api/public.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": [{
3 | "imgSrc": "http://wfqqreader.3g.qq.com/cover/200/835200/t3_835200.jpg",
4 | "title": "顾盼生辉",
5 | "des": "晋江人气作者夜蔓首部温暖之作,治愈每一段抱憾人生的手语之爱。因为遇见你,我才喜欢上雪天;也是因为遇见你,我才知道原来生活还有另一种可能。开间工作室,还有一家咖啡厅,里面放着翻不完的漫画书;养一只波斯猫,一个人的时候也不会觉得孤独。她想就这样过一辈子也挺好,如果陈绍宸没有出现的话……她一直记得那天,雪花纷飞,彻骨寒冷,他说:“你比画,我应该能看得懂。”从遇见她的那一刻起,他便以自己的方式守护她成长。宸,北极星的所在。永远北方的指向,航海的人们通过它来辨别方向,而陈绍宸是顾盼的方向。婚礼上,他拥着她,在她耳边沉声道:“从此,我便是你的声音,你比画,我来说。”只因遇见你,所有的遗憾便都不再是遗憾",
6 | "type": "夜蔓 / 青春",
7 | "status": "end",
8 | "id": "1"
9 | }, {
10 | "imgSrc": "http://wfqqreader.3g.qq.com/cover/826/913826/t3_913826.jpg",
11 | "title": "韩先生,我想请你结个婚",
12 | "des": "黑暗中,她为救他,成了他的女人,他却隔天清晨匆匆离去。六年后,她进入他的公司,与他擦肩而过,却互不相识,但一切却悄然发生改变,他有了自己爱的人,她有了爱自己的人......她带着女儿疲于奔命,他重新进入她的生活,当他决定娶她时,她却淡淡一笑,转身离开",
13 | "type": "顾伊雪 / 青春",
14 | "status": "update",
15 | "id": "2"
16 | }]
17 | }
--------------------------------------------------------------------------------
/src/components/BookDetails.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { NavBar, Icon } from 'antd-mobile';
3 | import './BookDetails.scss';
4 |
5 | class BookDetails extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | };
10 | this.back = this.back.bind(this);
11 | }
12 | componentDidMount() {
13 | }
14 | back() {
15 | this.props.history.push('/');
16 | }
17 | render() {
18 | return (
19 |
20 |
,
26 | '书城'
27 | ]}
28 | >简介
29 |
30 | {this.props.match.params.id}
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default BookDetails;
38 |
--------------------------------------------------------------------------------
/config/polyfills.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | if (typeof Promise === 'undefined') {
4 | // Rejection tracking prevents a common issue where React gets into an
5 | // inconsistent state due to an error, but it gets swallowed by a Promise,
6 | // and the user has no idea what causes React's erratic future behavior.
7 | require('promise/lib/rejection-tracking').enable();
8 | window.Promise = require('promise/lib/es6-extensions.js');
9 | }
10 |
11 | // fetch() polyfill for making API calls.
12 | require('whatwg-fetch');
13 |
14 | // Object.assign() is commonly used with React.
15 | // It will use the native implementation if it's present and isn't buggy.
16 | Object.assign = require('object-assign');
17 |
18 | // In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet.
19 | // We don't polyfill it in the browser--this is user's responsibility.
20 | if (process.env.NODE_ENV === 'test') {
21 | require('raf').polyfill(global);
22 | }
23 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | BrowserRouter as Router,
4 | Route
5 | } from 'react-router-dom';
6 | import Bookstore from './components/Bookstore.js';
7 | import BookDetails from './components/BookDetails.js';
8 | import Search from './components/Search.js';
9 |
10 | import './App.css';
11 | import 'antd-mobile/dist/antd-mobile.css';
12 |
13 | class App extends Component {
14 | constructor(props) {
15 | super(props);
16 | this.state = {
17 | };
18 | }
19 | componentDidMount() {
20 | }
21 | render() {
22 | return (
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 | }
35 |
36 | export default App;
37 |
--------------------------------------------------------------------------------
/src/components/Search.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { NavBar, Icon, SearchBar } from 'antd-mobile';
3 | import './Search.scss';
4 |
5 | class Search extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | value: ''
10 | };
11 | }
12 | componentDidMount() {
13 | }
14 | onChange= (value) => {
15 | this.setState({ value });
16 | }
17 | render() {
18 | return (
19 | this.props.history.push('/')}
23 | leftContent={[
24 | ,
25 | '书城'
26 | ]}
27 | >搜索
28 | this.autoFocusInst = ref}
34 | />
35 |
);
36 | }
37 | }
38 |
39 | export default Search;
40 |
--------------------------------------------------------------------------------
/src/components/FilterWrap.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './FilterWrap.scss';
3 |
4 | class FilterWrap extends Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = {};
8 | }
9 | componentDidMount() {
10 | this.props.typeData&&this.getBookList(this.props.typeData[0].id);
11 | }
12 | getBookList (id, e) {
13 | this.props.getBookList(id);
14 | }
15 | render() {
16 | return (
17 |
18 |
19 |
20 |
{this.props.title || '默认标题'}
21 |
22 |
23 |
24 | {
25 | this.props.typeData&&this.props.typeData.map(item => (
26 | -
30 | {item.name}
31 | ))
32 | }
33 |
34 |
35 | );
36 | }
37 | }
38 |
39 |
40 | export default FilterWrap;
41 |
--------------------------------------------------------------------------------
/src/components/FilterWrap.scss:
--------------------------------------------------------------------------------
1 | .filter-wrap {
2 | padding: 16px 0;
3 | background-color: #fafafa;
4 | .filter-item-title {
5 | text-align: center;
6 | span {
7 | display: inline-block;
8 | vertical-align: middle;
9 | width: 16px;
10 | height: 1px; background-color: #e5e5e5;
11 | }
12 | span::after {
13 | content: '';
14 | position: absolute;
15 | height: 1px;
16 | top: 0;
17 | -webkit-transform: scaleY(.5);
18 | -ms-transform: scaleY(.5);
19 | transform: scaleY(.5);
20 | -webkit-transform-origin: 0 0;
21 | -ms-transform-origin: 0 0;
22 | transform-origin: 0 0;
23 | pointer-events: none;
24 | left: 0;
25 | right: 0;
26 | background-color: #e5e5e5;
27 | }
28 | h1 {
29 | display: inline-block;
30 | margin: 0 16px;;
31 | font-size: 0.75rem;
32 | font-weight: 400;
33 | color: #8f8f8f;
34 | }
35 | }
36 | .filter-item-wrap {
37 | display: flex;
38 | list-style: none;
39 | padding: 0;
40 | margin-bottom: 0;
41 | li {
42 | flex: 1;
43 | font-size: 0.85rem;
44 | color: #242424;
45 | }
46 | li:nth-child(2) {
47 | border-left: 1px solid #e5e5e5;
48 | border-right: 1px solid #e5e5e5;
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/components/InfoItemList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import './InfoItemList.scss';
4 |
5 | class InfoItemList extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {};
9 | }
10 | componentDidMount() {
11 | }
12 | render() {
13 | return (
14 |
15 | {
16 | this.props.data.map(item => (
17 | -
18 |
21 |
22 |

23 |
24 |
25 |
{item.title}
26 |
{item.des}
27 |
28 |
29 | {item.type}
30 |
31 |
32 |
33 |
34 | ))
35 | }
36 | 更多...
37 |
38 | );
39 | }
40 | }
41 |
42 | export default InfoItemList;
43 |
--------------------------------------------------------------------------------
/src/api/boy.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": [{
3 | "imgSrc": "http://wfqqreader.3g.qq.com/cover/537/15808537/t3_15808537.jpg",
4 | "title": "大帝姬",
5 | "des": "穿越的薛青发现自己女扮男装在骗婚。不仅如此她还有一个更大的骗局。这是一个有很多秘密的人的故事",
6 | "type": "希行 / 古言",
7 | "status": "end",
8 | "id": "1"
9 | }, {
10 | "imgSrc": "http://wfqqreader.3g.qq.com/cover/305/20304305/t3_20304305.jpg",
11 | "title": "恰似寒光遇骄阳",
12 | "des": "这家伙,口味是有多重,这都下得去口?”一觉醒来,她看着镜子里的自己,爆炸头血腥纹身脸化得像鬼,多看一秒都辣眼睛。重生前,她另有所爱,一心逃离,与他发生关系后对他恨之入骨。重生后,她瞄了眼床上的美色,严肃思考,这事后留下阴影的,貌似应该是他?上一世脑子被门夹了放着绝色老公不要,被渣男贱女所害,被最信任的闺密洗脑,落了个众叛亲离的下场。这一世,任各路牛鬼蛇神处心积虑巴不得她离婚让位,不好意思,本小姐智商上线了!",
13 | "type": "囧囧有妖 / 现言",
14 | "status": "update",
15 | "id": "2"
16 | }, {
17 | "imgSrc": "http://wfqqreader.3g.qq.com/cover/200/835200/t3_835200.jpg",
18 | "title": "顾盼生辉",
19 | "des": "晋江人气作者夜蔓首部温暖之作,治愈每一段抱憾人生的手语之爱。因为遇见你,我才喜欢上雪天;也是因为遇见你,我才知道原来生活还有另一种可能。开间工作室,还有一家咖啡厅,里面放着翻不完的漫画书;养一只波斯猫,一个人的时候也不会觉得孤独。她想就这样过一辈子也挺好,如果陈绍宸没有出现的话……她一直记得那天,雪花纷飞,彻骨寒冷,他说:“你比画,我应该能看得懂。”从遇见她的那一刻起,他便以自己的方式守护她成长。宸,北极星的所在。永远北方的指向,航海的人们通过它来辨别方向,而陈绍宸是顾盼的方向。婚礼上,他拥着她,在她耳边沉声道:“从此,我便是你的声音,你比画,我来说。”只因遇见你,所有的遗憾便都不再是遗憾",
20 | "type": "夜蔓 / 青春",
21 | "status": "end",
22 | "id": "3"
23 | }, {
24 | "imgSrc": "http://wfqqreader.3g.qq.com/cover/826/913826/t3_913826.jpg",
25 | "title": "韩先生,我想请你结个婚",
26 | "des": "黑暗中,她为救他,成了他的女人,他却隔天清晨匆匆离去。六年后,她进入他的公司,与他擦肩而过,却互不相识,但一切却悄然发生改变,他有了自己爱的人,她有了爱自己的人......她带着女儿疲于奔命,他重新进入她的生活,当他决定娶她时,她却淡淡一笑,转身离开",
27 | "type": "顾伊雪 / 青春",
28 | "status": "update",
29 | "id": "4"
30 | }]
31 | }
--------------------------------------------------------------------------------
/src/static/svg/reader.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Bookstore.scss:
--------------------------------------------------------------------------------
1 | .Bookstore {
2 | background-color: #ebebeb;
3 | .nav-bar {
4 | background-color: #e87646 !important;
5 | color: #fff !important;
6 | .am-navbar-title {
7 | color: #fff !important;
8 | }
9 | }
10 | .am-carousel {
11 | .am-carousel-wrap {
12 | text-align: right;
13 | }
14 | }
15 | .am-grid {
16 | .am-flexbox {
17 | background: #fafafa !important;
18 | }
19 | &.am-grid-square {
20 | background-color: #fafafa;
21 | .am-grid-item {
22 | .am-grid-item-inner-content {
23 | .am-grid-icon {
24 | width: 40% !important;
25 | }
26 | .am-grid-text {
27 | font-size: 0.85rem !important;
28 | }
29 | }
30 | }
31 | }
32 | }
33 | .book-list-wrap {
34 | background-color: #fafafa;
35 | margin-top: 8px;
36 | h1 {
37 | position: relative;
38 | font-size: 0.85rem;
39 | font-weight: 400;
40 | margin: 0 16px;
41 | padding: 14px 0;
42 | text-align: left;
43 | color: #000;
44 | }
45 | h1::after {
46 | content: '';
47 | position: absolute;
48 | height: 1px;
49 | bottom: 0;
50 | -webkit-transform: scaleY(.5);
51 | -ms-transform: scaleY(.5);
52 | transform: scaleY(.5);
53 | -webkit-transform-origin: 0 100%;
54 | -ms-transform-origin: 0 100%;
55 | transform-origin: 0 100%;
56 | pointer-events: none;
57 | left: 0;
58 | right: 0;
59 | background-color: #e5e5e5;
60 | }
61 | .b-tags {
62 | float: left;
63 | list-style: none;
64 | padding: 0 16px;
65 | li {
66 | float: left;
67 | display: inline-block;
68 | width: 52px;
69 | height: 30px;
70 | line-height: 30px;
71 | margin-right: 8px;
72 | font-size: 0.85rem;
73 | border: 1px solid #e5e5e5;
74 | border-radius: 40px;
75 | }
76 | }
77 | .b-view-more {
78 | height: 44px;
79 | line-height: 44px;
80 | font-size: 0.85rem;
81 | color: #666;
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const url = require('url');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebookincubator/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL;
13 |
14 | function ensureSlash(path, needsSlash) {
15 | const hasSlash = path.endsWith('/');
16 | if (hasSlash && !needsSlash) {
17 | return path.substr(path, path.length - 1);
18 | } else if (!hasSlash && needsSlash) {
19 | return `${path}/`;
20 | } else {
21 | return path;
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage;
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right
24 |
34 | React App
35 |
36 |
37 |
40 |
41 |
51 |
52 |