├── app2 ├── src │ ├── components │ │ ├── Loading │ │ │ ├── README.md │ │ │ ├── index.css │ │ │ └── index.js │ │ ├── Markeder │ │ │ ├── README.md │ │ │ └── index.js │ │ ├── TopTips │ │ │ ├── README.md │ │ │ └── index.js │ │ ├── ListTitle │ │ │ ├── README.md │ │ │ └── index.js │ │ ├── ArticleTitle │ │ │ ├── README.md │ │ │ └── index.js │ │ ├── Footer │ │ │ └── index.js │ │ └── Header │ │ │ └── index.js │ ├── index.css │ ├── pages │ │ ├── Detail │ │ │ ├── index.css │ │ │ └── index.js │ │ ├── Test │ │ │ └── index.js │ │ ├── Life │ │ │ └── index.js │ │ ├── AdminDetail │ │ │ └── index.js │ │ ├── Blog │ │ │ └── index.js │ │ ├── PostArticle │ │ │ └── index.js │ │ ├── Login │ │ │ └── index.js │ │ └── Admin │ │ │ └── index.js │ ├── contains │ │ ├── common │ │ │ └── index.js │ │ ├── backEnd │ │ │ └── index.js │ │ └── fontEnd │ │ │ └── index.js │ ├── App.test.js │ ├── App.css │ ├── index.js │ ├── actions.js │ ├── until │ │ └── index.js │ ├── App.js │ ├── logo.svg │ ├── reducers.js │ └── registerServiceWorker.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── config │ ├── jest │ │ ├── fileTransform.js │ │ └── cssTransform.js │ ├── polyfills.js │ ├── paths.js │ ├── env.js │ ├── webpackDevServer.config.js │ ├── webpack.config.dev.js │ └── webpack.config.prod.js ├── .gitignore ├── server │ ├── index.js │ ├── app.prod.js │ ├── views │ │ └── index.ejs │ └── app.dev.js ├── README.md ├── scripts │ ├── test.js │ ├── start.js │ └── build.js └── package.json ├── koa2-router-demo ├── routerUrl │ └── index.js ├── views │ ├── index.pug │ ├── error.pug │ └── layout.pug ├── public │ ├── stylesheets │ │ └── style.css │ └── index.html ├── config │ └── index.js ├── .idea │ ├── modules.xml │ ├── tesst-koa-proxy.iml │ └── workspace.xml ├── routes │ ├── users.js │ └── index.js ├── .gitignore ├── README.md ├── until │ └── index.js ├── sql │ ├── common │ │ └── index.js │ ├── backEnd │ │ └── index.js │ └── frontEnd │ │ └── index.js ├── package.json ├── test.html ├── app.js ├── bin │ └── www ├── models │ └── user.js └── test.js ├── .idea ├── watcherTasks.xml ├── misc.xml ├── vcs.xml ├── modules.xml └── a-my-react-blog-index.iml ├── .gitignore └── README.md /app2/src/components/Loading/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /koa2-router-demo/routerUrl/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app2/src/components/Markeder/README.md: -------------------------------------------------------------------------------- 1 | # 这是详情页面和后台编辑页面公用的文档编辑 2 | -------------------------------------------------------------------------------- /app2/src/components/TopTips/README.md: -------------------------------------------------------------------------------- 1 | # 这是每个页面顶部的提示 2 | 现在的github和开发中 -------------------------------------------------------------------------------- /app2/src/components/ListTitle/README.md: -------------------------------------------------------------------------------- 1 | # 这是列表页面的显示 2 | 生活夜念和文章列表页面 3 | -------------------------------------------------------------------------------- /app2/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Weibozzz/react-blog/HEAD/app2/public/favicon.ico -------------------------------------------------------------------------------- /app2/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /app2/src/pages/Detail/index.css: -------------------------------------------------------------------------------- 1 | .detail-info li{ 2 | margin-right: 20px; 3 | } 4 | .test{ 5 | color: red; 6 | } -------------------------------------------------------------------------------- /koa2-router-demo/views/index.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /koa2-router-demo/views/error.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /app2/src/contains/common/index.js: -------------------------------------------------------------------------------- 1 | export const domain = 'http://localhost:7654'; 2 | export const github = 'https://api.github.com/repos/Weibozzz/react-blog'; 3 | -------------------------------------------------------------------------------- /.idea/watcherTasks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /koa2-router-demo/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /koa2-router-demo/views/layout.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app2/src/components/Loading/index.css: -------------------------------------------------------------------------------- 1 | .loading-wrapper{ 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | height: 300px; 6 | background-color: #f0f2f5; 7 | } 8 | .spin-wrapper{ 9 | height: 100px; 10 | } -------------------------------------------------------------------------------- /koa2-router-demo/config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | database: { 3 | host: 'localhost', 4 | user: 'root', 5 | password: '', 6 | database: 'blog' 7 | }, 8 | devide_time:1526625828 //这个包括时间之后存入数据库的是markdown格式 9 | } 10 | 11 | 12 | -------------------------------------------------------------------------------- /app2/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 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /koa2-router-demo/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /koa2-router-demo/routes/users.js: -------------------------------------------------------------------------------- 1 | const router = require('koa-router')() 2 | 3 | router.prefix('/users') 4 | 5 | router.get('/', function (ctx, next) { 6 | ctx.body = 'this is a users response!' 7 | }) 8 | 9 | router.get('/bar', function (ctx, next) { 10 | ctx.body = 'this is a users/bar response' 11 | }) 12 | 13 | module.exports = router 14 | -------------------------------------------------------------------------------- /koa2-router-demo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |

test-api

11 | 12 | -------------------------------------------------------------------------------- /app2/src/components/Loading/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Spin} from 'antd'; 3 | import './index.css' 4 | const Loading = (props)=> ( 5 |
6 |
7 | 8 |
9 |
10 | ) 11 | export default Loading -------------------------------------------------------------------------------- /app2/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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.idea 6 | 7 | # testing 8 | /coverage 9 | 10 | # production 11 | /build 12 | 13 | # misc 14 | .DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /app2/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.idea 6 | 7 | # testing 8 | /coverage 9 | 10 | # production 11 | /build 12 | 13 | # misc 14 | .DS_Store 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /app2/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 | -------------------------------------------------------------------------------- /app2/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 | -------------------------------------------------------------------------------- /koa2-router-demo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /app2/src/components/ArticleTitle/README.md: -------------------------------------------------------------------------------- 1 | # 文章详情的其他信息 2 | ``` 3 | { 4 | content, 5 | createTime, 6 | id, 7 | img, 8 | lastModify, 9 | like, 10 | modifyCount, 11 | recommend, 12 | short, 13 | title, 14 | type, 15 | url, 16 | user, 17 | visitor, 18 | week 19 | } 20 | 21 | ``` -------------------------------------------------------------------------------- /app2/server/index.js: -------------------------------------------------------------------------------- 1 | const isProductionMode = (process.env.NODE_ENV ==='production'); 2 | const app = isProductionMode ? require ('./app.prod.js') : require('./app.dev.js'); 3 | if (!isProductionMode) { 4 | process.env.NODE_ENV = 'development'; 5 | } 6 | const PORT = process.env.PORT ||9001; 7 | app.listen(PORT, function() { 8 | console.log ('running in '+ (isProductionMode ?'production':'development')+ ' mode') 9 | console.log ('listening on port:'+ PORT); 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /.idea/a-my-react-blog-index.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app2/src/components/Footer/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Layout, Menu, Breadcrumb ,Row,Col} from 'antd'; 3 | const { Header, Content, Footer } = Layout; 4 | class blogFooter extends Component { 5 | render() { 6 | return ( 7 | 11 | ); 12 | } 13 | } 14 | 15 | export default blogFooter; 16 | -------------------------------------------------------------------------------- /koa2-router-demo/.idea/tesst-koa-proxy.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /koa2-router-demo/README.md: -------------------------------------------------------------------------------- 1 | # 后端说明 2 | ## 运行 3 | ``` 4 | npm install 5 | npm start 6 | ``` 7 | ## 项目文件夹说明 8 | ``` 9 | E:\project\myself\ctrl\aa\react-blog\koa2-router-demo 10 | ├─.gitignore 11 | ├─app.js 12 | ├─package.json 13 | ├─views 14 | | ├─error.pug 15 | | ├─index.pug 16 | | └layout.pug 17 | ├─until // 前端调用的所有接口,返回的是所有的sql语句 18 | | ├─frontEnd 19 | | | └index.js 20 | | ├─common 21 | | | └index.js 22 | | ├─backEnd 23 | | | └index.js 24 | ├─routes 25 | | ├─index.js // 请求文件,发送sql请求 26 | | └users.js 27 | ``` -------------------------------------------------------------------------------- /koa2-router-demo/until/index.js: -------------------------------------------------------------------------------- 1 | const saveHtml = str => { 2 | return str.replace(/'|"/g, function (str) { 3 | if (str === '"') { 4 | return '@quot;' 5 | } else if (str === "'") { 6 | return '@apos;' 7 | } 8 | }); 9 | } 10 | const getURLParameters = url => 11 | url.match(/([^?=&]+)(=([^&]*))/g).reduce( 12 | (a, v) => (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1), a), {} 13 | ) 14 | const spaceAdd = str => str && str.replace(/\+/g, ' ') 15 | module.exports = { 16 | saveHtml, 17 | spaceAdd, 18 | getURLParameters 19 | } -------------------------------------------------------------------------------- /app2/server/app.prod.js: -------------------------------------------------------------------------------- 1 | const express = require ('express') ; 2 | const path= require ('path'); 3 | 4 | const app =express(); 5 | const assetManifest = require(path.resolve(__dirname,'../build/asset-manifest.json')); 6 | 7 | app.use(express.static(path.resolve(__dirname,'../build'))) 8 | 9 | app.get('*',(req,res)=>{ 10 | return res.render('index',{ 11 | title:'lwb-lwb-lwb', 12 | PUBLIC_URL:'/', 13 | assetManifest:assetManifest 14 | }) 15 | }) 16 | 17 | app.set('view engine','ejs') 18 | app.set('views',path.resolve(__dirname,'views')) 19 | 20 | module.exports=app; -------------------------------------------------------------------------------- /app2/src/App.css: -------------------------------------------------------------------------------- 1 | @import '~antd/dist/antd.css'; 2 | 3 | pre{ 4 | background-color: #f5f5f5; 5 | border: 1px solid #ccc; 6 | } 7 | .fl{ 8 | float: left; 9 | } 10 | .fr{ 11 | float: right; 12 | } 13 | .clearfix:after{ 14 | content: ''; 15 | clear: both; 16 | display: block; 17 | } 18 | ul{ 19 | margin: 0; 20 | padding: 0; 21 | } 22 | li{ 23 | list-style: none; 24 | } 25 | #root,.container{ 26 | height: 100%; 27 | min-height: 100%; 28 | } 29 | .container{ 30 | display: flex; 31 | flex-direction: column; 32 | background-color: #f0f2f5; 33 | } 34 | .mid-content{ 35 | flex-grow: 1; 36 | } 37 | -------------------------------------------------------------------------------- /koa2-router-demo/sql/common/index.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql') 2 | const pool = mysql.createPool({ 3 | host: 'localhost', 4 | user: 'root', 5 | password: '', 6 | database: 'blog' 7 | }) 8 | 9 | let querySql = ( sql )=> { 10 | return new Promise((resolve, reject) => { 11 | pool.getConnection((err, connection) => { 12 | // Use the connection 13 | connection.query(sql, (error, results, fields) => { 14 | // And done with the connection. 15 | resolve(JSON.stringify(results)) 16 | connection.release() 17 | // Handle error after the release. 18 | if (error) throw error 19 | }) 20 | }) 21 | }) 22 | } 23 | 24 | module.exports = { 25 | querySql 26 | } -------------------------------------------------------------------------------- /app2/server/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ooo 10 | 11 | 12 | 13 | 14 |
15 |
32323
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app2/README.md: -------------------------------------------------------------------------------- 1 | # 前端说明 2 | ## 运行 3 | ``` 4 | npm install 5 | npm start 6 | ``` 7 | ## 项目文件夹说明 8 | ``` 9 | ├─actions.js // redux 10 | ├─App.css 11 | ├─App.js 12 | ├─App.test.js 13 | ├─index.css 14 | ├─index.js 15 | ├─logo.svg 16 | ├─reducers.js // redux 17 | ├─registerServiceWorker.js 18 | ├─until 19 | | └index.js // 工具库 20 | ├─pages // 所有的页面 21 | | ├─Detail 22 | | | └index.js 23 | | ├─Blog 24 | | | └index.js 25 | | ├─AdminDetail 26 | | | └index.js 27 | | ├─Admin 28 | | | └index.js 29 | ├─contains // 所有的数据请求 30 | | ├─fontEnd 31 | | | └index.js 32 | | ├─common 33 | | | └index.js 34 | | ├─backEnd 35 | | | └index.js 36 | ├─components // 所有的公用组件 37 | | ├─Header 38 | | | └index.js 39 | | ├─Footer 40 | | | └index.js 41 | ``` 42 | -------------------------------------------------------------------------------- /koa2-router-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tesst-koa-proxy", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node bin/www", 7 | "dev": "./node_modules/.bin/nodemon bin/www", 8 | "prd": "pm2 start bin/www", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "dependencies": { 12 | "debug": "^2.6.3", 13 | "koa": "^2.2.0", 14 | "koa-body": "^2.5.0", 15 | "koa-bodyparser": "^3.2.0", 16 | "koa-convert": "^1.2.0", 17 | "koa-json": "^2.0.2", 18 | "koa-logger": "^2.0.1", 19 | "koa-onerror": "^1.2.1", 20 | "koa-router": "^7.3.1", 21 | "koa-static": "^3.0.0", 22 | "koa-views": "^5.2.1", 23 | "mysql": "^2.15.0", 24 | "pug": "^2.0.0-rc.1" 25 | }, 26 | "devDependencies": { 27 | "nodemon": "^1.8.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app2/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 | let 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 | -------------------------------------------------------------------------------- /koa2-router-demo/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 23 | 24 | 25 | 26 |
27 |
b1
28 |
b2
29 |
b3
30 |
31 | 32 | 33 | 36 | 37 | -------------------------------------------------------------------------------- /app2/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | // import {createStore,applyMiddleware} from 'redux'; 7 | import { createStore, combineReducers, applyMiddleware } from 'redux' 8 | import {Provider} from 'react-redux'; 9 | import { ConnectedRouter, routerReducer, routerMiddleware, push } from 'react-router-redux' 10 | import myBlog from './reducers'; 11 | import thunkMiddleWare from 'redux-thunk' 12 | import registerServiceWorker from './registerServiceWorker'; 13 | 14 | let store = createStore(myBlog, 15 | window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), 16 | applyMiddleware(thunkMiddleWare) 17 | ); 18 | 19 | 20 | ReactDOM.render( 21 | 22 | 23 | 24 | , document.getElementById('root')); 25 | registerServiceWorker(); 26 | 27 | -------------------------------------------------------------------------------- /app2/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 | -------------------------------------------------------------------------------- /koa2-router-demo/app.js: -------------------------------------------------------------------------------- 1 | const Koa = require('koa') 2 | const app = new Koa() 3 | const views = require('koa-views') 4 | const json = require('koa-json') 5 | const onerror = require('koa-onerror') 6 | const bodyparser = require('koa-bodyparser') 7 | const logger = require('koa-logger') 8 | 9 | const index = require('./routes/index') 10 | const users = require('./routes/users') 11 | 12 | // error handler 13 | onerror(app) 14 | 15 | // middlewares 16 | app.use(bodyparser({ 17 | enableTypes:['json', 'form', 'text'] 18 | })) 19 | app.use(json()) 20 | app.use(logger()) 21 | app.use(require('koa-static')(__dirname + '/public')) 22 | 23 | app.use(views(__dirname + '/views', { 24 | extension: 'pug' 25 | })) 26 | 27 | // logger 28 | app.use(async (ctx, next) => { 29 | const start = new Date() 30 | await next() 31 | const ms = new Date() - start 32 | console.log(`${ctx.method} ${ctx.url} - ${ms}ms`) 33 | }) 34 | 35 | // routes 36 | app.use(index.routes(), index.allowedMethods()) 37 | app.use(users.routes(), users.allowedMethods()) 38 | 39 | // error-handling 40 | app.on('error', (err, ctx) => { 41 | console.error('server error', err, ctx) 42 | }); 43 | 44 | module.exports = app 45 | -------------------------------------------------------------------------------- /app2/src/components/TopTips/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Layout, Menu, Breadcrumb, Row, Col } from 'antd' 3 | import { List, Avatar, Icon,Pagination,Alert,Input,Button,Radio,Tooltip } from 'antd' 4 | 5 | 6 | 7 | class TopTips extends Component { 8 | componentWillReceiveProps(){ 9 | //任何子页面发生改变,均可调用,完成路径切分以及形成面包屑 10 | } 11 | render () { 12 | return ( 13 |
14 | 20 |
21 | 22 |
23 | 24 | 网站首页 25 | 前端技术 26 | 171 27 | 28 |
29 | ) 30 | } 31 | } 32 | 33 | export default TopTips 34 | -------------------------------------------------------------------------------- /app2/src/pages/Test/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | const ReactMarkdown = require('react-markdown') 4 | 5 | const input = '\n' + 6 | '# Live demo\n' + 7 | '\n' + 8 | 'Changes are automatically rendered as you type.\n' + 9 | '\n' + 10 | '* Implements [GitHub Flavored Markdown](https://github.github.com/gfm/)\n' + 11 | '* Renders actual, "native" React DOM elements\n' + 12 | '* Allows you to escape or skip HTML (try toggling the checkboxes above)\n' + 13 | '* If you escape or skip the HTML, no `dangerouslySetInnerHTML` is used! Yay!\n' + 14 | '\n' + 15 | '## HTML block below\n' + 16 | '\n' + 17 | '
\n' + 18 | ' This blockquote will change based on the HTML settings above.\n' + 19 | '
\n' + 20 | '\n' + 21 | '## How about some code?\n' + 22 | '```js\n' + 23 | 'var React = require(\'react\');\n' + 24 | 'var Markdown = require(\'react-markdown\');\n' + 25 | '\n' + 26 | 'React.render(\n' + 27 | ' ,\n' + 28 | ' document.getElementById(\'content\')\n' + 29 | ');\n' + 30 | '```' 31 | class Test extends React.Component { 32 | render() { 33 | return ( 34 |
35 | , 36 |
37 | ); 38 | } 39 | } 40 | export default Test; -------------------------------------------------------------------------------- /app2/src/components/ArticleTitle/index.js: -------------------------------------------------------------------------------- 1 | import React,{Component} from 'react'; 2 | import { List, Avatar, Icon ,Divider} from 'antd'; 3 | import {formatTime,getArticleInfo} from '../../until'; 4 | 5 | class ArticleTitle extends Component{ 6 | 7 | constructor() { 8 | super() 9 | this.state = { 10 | } 11 | } 12 | 13 | 14 | render(){ 15 | let { 16 | content, 17 | createTime, 18 | id, 19 | img, 20 | lastModify, 21 | like, 22 | modifyCount, 23 | recommend, 24 | short, 25 | title, 26 | type, 27 | url, 28 | user, 29 | visitor, 30 | week 31 | }=getArticleInfo(this.props.detail); 32 | 33 | return ( 34 | 35 |
36 |

{title}

37 |
    38 |
  • 发布时间:{formatTime(createTime)}
  • 39 |
  • 作者:{user}
  • 40 |
  • 浏览次数:{visitor}
  • 41 |
  • 最后修改:{formatTime(lastModify)}
  • 42 |
  • 修改次数:{modifyCount}
  • 43 |
44 | 45 |
46 | ) 47 | } 48 | } 49 | 50 | export default ArticleTitle -------------------------------------------------------------------------------- /app2/server/app.dev.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | 4 | // const renderPage = require('./routes.Server.js').renderPage; 5 | 6 | const webpack = require('webpack'); 7 | const webpackConfig = require('../config/webpack.config.dev.js'); 8 | const middleware = require('webpack-dev-middleware'); 9 | const compiler = webpack(webpackConfig); 10 | const webpackDevMiddleware = middleware( 11 | compiler, 12 | { 13 | noInfo: true, 14 | publicPath: webpackConfig.output.publicPath 15 | }); 16 | 17 | function getAssetManifest() { 18 | const content = webpackDevMiddleware.fileSystem.readFileSync(__dirname + '/../build/asset-manifest.json'); 19 | return JSON.parse(content); 20 | } 21 | 22 | const app = express(); 23 | 24 | let assetManifest = null; 25 | 26 | app.use(express.static(path.resolve(__dirname, '../build'))); 27 | 28 | app.use(webpackDevMiddleware); 29 | app.use(require('webpack-hot-middleware')(compiler, { 30 | log: console.log, 31 | path: '/__webpack_hmr', 32 | heartbeat: 10 * 1000 33 | })); 34 | 35 | // app.use('/api/count', (req, res) => { 36 | // res.json({count: 100}); 37 | // }); 38 | 39 | app.get('*', (req, res) => { 40 | const assetManifest = getAssetManifest(); 41 | return res.render('index', { 42 | title: 'Sample React App', 43 | PUBLIC_URL: '/', 44 | assetMan_fest: assetManifest 45 | }); 46 | }) 47 | 48 | app.set('view engine', 'ejs'); 49 | app.set('views', path.resolve(__dirname, 'views')); 50 | 51 | module.exports = app; 52 | -------------------------------------------------------------------------------- /app2/src/pages/Life/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Layout, Menu, Breadcrumb, Row, Col } from 'antd' 3 | import { List, Avatar, Icon,Pagination,Alert,Input,Button,Radio,Tooltip } from 'antd' 4 | import { connect } from 'react-redux' 5 | import Header from '../../components/Header' 6 | import Footer from '../../components/Footer' 7 | import { 8 | BrowserRouter as Router, 9 | HashRouter, 10 | Route, 11 | Link 12 | } from 'react-router-dom' 13 | import { asyncTest,getTotal } from '../../actions' 14 | import 'whatwg-fetch' 15 | import {getBlogUrl,getTotalUrl,getBlogData,getTotalData,_getTotalData,_getBlogData,getLifeData,getLifeUrl} from '../../contains/fontEnd' 16 | import Detail from '../Detail' 17 | import TopTips from '../../components/TopTips'; 18 | import {formatTime} from "../../until"; 19 | import ListTitle from '../../components/ListTitle'; 20 | import Loading from '../../components/Loading'; 21 | 22 | const {Content} = Layout 23 | 24 | 25 | 26 | class Life extends Component { 27 | componentWillMount(){ 28 | this.props.dispatch(getLifeData(getLifeUrl)); 29 | } 30 | render () { 31 | return ( 32 |
33 | 34 | 35 | 36 |
37 | 38 |
39 |
40 |
41 |
42 | ) 43 | } 44 | } 45 | 46 | const select = (state) => { 47 | console.log(state) 48 | return { 49 | life:state.life 50 | } 51 | } 52 | // export default Blog; 53 | export default connect(select)(Life) 54 | -------------------------------------------------------------------------------- /koa2-router-demo/sql/backEnd/index.js: -------------------------------------------------------------------------------- 1 | const {querySql, getURLParameters} = require('../common') 2 | 3 | const getAdminBlogSql = (type, startIndex, pageNum, wd) => { 4 | if (type === "all") { 5 | return "select `id`,`title`,`user`,`createTime`,`visitor`,`like`,`img`,`recommend` from article2" + 6 | " order by createTime desc limit " + startIndex + "," + pageNum + ""; 7 | // " order by concat(modifyCount,createTime) desc limit "+startIndex+","+pageNum+""; 8 | } else if (type === "title") { 9 | return "select `id`,`title`,`user`,`createTime`,week,`visitor`,`like`,`img`,`type` from article2" + 10 | " where title like '%" + decodeURIComponent(wd) + "%' order by createTime desc limit " + startIndex + "," + pageNum + ""; 11 | // " where title like '%"+decodeURIComponent(wd)+"%' order by concat(modifyCount,createTime) desc limit "+startIndex+","+pageNum+""; 12 | } else if(type==='del'){ 13 | return "delete from article2 where id="+startIndex 14 | } 15 | 16 | else { 17 | return "select `id`,`title`,`user`,`createTime`,week,`visitor`,`like`,`img`,`type` from article2" + 18 | " where type='" + type + "' order by concat(modifyCount,createTime) desc limit " + startIndex + "," + pageNum + ""; 19 | } 20 | } 21 | const postAdminDetailSql = (content, id) => { 22 | return "update `article2` set content='" + content + "' where `id`='" + id + "'"; 23 | } 24 | const getAdminCommentsSql = (a_id, id) => { 25 | if (a_id === 'all') { 26 | return id==null? 27 | "select * from comment order by createTime desc " 28 | :"delete from comment where id= " + id; 29 | } else { 30 | return "select * from comment where `a_id`=" + a_id + " order by createTime desc "; 31 | } 32 | } 33 | 34 | 35 | module.exports = { 36 | querySql, 37 | getAdminBlogSql, 38 | postAdminDetailSql, 39 | getURLParameters, 40 | getAdminCommentsSql 41 | 42 | } -------------------------------------------------------------------------------- /app2/src/contains/backEnd/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import {getAdminBlog, postAdminDetail,getAdminComments} from '../../actions' 3 | 4 | import {domain} from '../common'; 5 | 6 | var qs = require("qs"); 7 | export const getAdminBlogUrl = domain + '/api/getAdminBlog' 8 | export const getAdminCommentsUrl = domain + '/api/getAdminComments' 9 | export const postAdminDetailUrl = domain + '/api/postAdminDetail' 10 | 11 | 12 | export const getAdminCommentsData = url => { 13 | return dispatch => { 14 | axios.get(url).then(res => { 15 | dispatch(getAdminComments(res.data)) 16 | }) 17 | } 18 | } 19 | export const getAdminBlogData = url => { 20 | return dispatch => { 21 | axios.get(url).then(res => { 22 | dispatch(getAdminBlog(res.data)) 23 | }) 24 | } 25 | } 26 | export const postAdminDetailData = (url, data) => { 27 | return dispatch => { 28 | axios({ 29 | method: 'POST', 30 | url, 31 | data: qs.stringify(data), 32 | headers: {"Content-Type": "application/x-www-form-urlencoded",}, 33 | 34 | }).then(res => { 35 | dispatch(postAdminDetail(res.data)) 36 | }) 37 | } 38 | } 39 | 40 | export const _getAdminBlogData = (_this, type, num, pageNum, val) => { 41 | if(type==='del'){ 42 | return _this.props.dispatch(getAdminBlogData(`${getAdminBlogUrl}?type=${type}&num=${num}`)); 43 | } 44 | return val 45 | ? _this.props.dispatch(getAdminBlogData(`${getAdminBlogUrl}?type=${type}&num=${num}&pageNum=${pageNum}&wd=${val}`)) 46 | : _this.props.dispatch(getAdminBlogData(`${getAdminBlogUrl}?type=${type}&num=${num}&pageNum=${pageNum}`)) 47 | } 48 | export const _getAdminCommentsData = (_this, a_id, id) => { 49 | return id 50 | ? _this.props.dispatch(getAdminCommentsData(`${getAdminCommentsUrl}?a_id=${a_id}&id=${id}`)) 51 | : _this.props.dispatch(getAdminCommentsData(`${getAdminCommentsUrl}?a_id=${a_id}`)) 52 | } -------------------------------------------------------------------------------- /koa2-router-demo/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('demo:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '7654'); 16 | // app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app.callback()); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /app2/src/actions.js: -------------------------------------------------------------------------------- 1 | export const TEST_ASYNC = 'TEST_ASYNC'; 2 | export const GET_TOTAL = 'GET_TOTAL'; 3 | export const GET_DETAIL = 'GET_DETAIL'; 4 | export const GET_NEXT_ID = 'GET_NEXT_ID'; 5 | export const GET_LAST_ID = 'GET_LAST_ID'; 6 | export const GET_ADMIN_BLOG = 'GET_ADMIN_BLOG'; 7 | export const GET_LIFE = 'GET_LIFE'; 8 | export const GET_COMMENTS = 'GET_COMMENTS'; 9 | 10 | export const GET_ADMIN_COMMENTS = 'GET_ADMIN_COMMENTS'; 11 | 12 | export const POST_ADMIN_DETAIL = 'POST_ADMIN_DETAIL'; 13 | export const POST_ARTICLE = 'POST_ARTICLE'; 14 | export const POST_COMMENT = 'POST_COMMENT'; 15 | 16 | 17 | // 异步请求 18 | 19 | export const asyncTest = data =>{ 20 | return { 21 | type:TEST_ASYNC, 22 | data 23 | } 24 | }; 25 | export const getTotal = data =>{ 26 | return { 27 | type:GET_TOTAL, 28 | data 29 | } 30 | }; 31 | export const getDetail = data =>{ 32 | return { 33 | type:GET_DETAIL, 34 | data 35 | } 36 | }; 37 | export const getLastId = data =>{ 38 | return { 39 | type:GET_LAST_ID, 40 | data 41 | } 42 | }; 43 | export const getNextId = data =>{ 44 | return { 45 | type:GET_NEXT_ID, 46 | data 47 | } 48 | }; 49 | export const getComments = data =>{ 50 | return { 51 | type:GET_COMMENTS, 52 | data 53 | } 54 | }; 55 | export const getAdminComments = data =>{ 56 | return { 57 | type:GET_ADMIN_COMMENTS, 58 | data 59 | } 60 | }; 61 | export const getLife = data =>{ 62 | return { 63 | type:GET_LIFE, 64 | data 65 | } 66 | }; 67 | export const getAdminBlog = data =>{ 68 | return { 69 | type:GET_ADMIN_BLOG, 70 | data 71 | } 72 | }; 73 | export const postAdminDetail = data =>{ 74 | return { 75 | type:POST_ADMIN_DETAIL, 76 | data 77 | } 78 | }; 79 | export const postArticle = data =>{ 80 | return { 81 | type:POST_ARTICLE, 82 | data 83 | } 84 | }; 85 | export const postComment = data =>{ 86 | return { 87 | type:POST_COMMENT, 88 | data 89 | } 90 | }; -------------------------------------------------------------------------------- /app2/src/until/index.js: -------------------------------------------------------------------------------- 1 | 2 | let format = require('date-format'); 3 | export const updateHtml=str=>{ 4 | return str.replace(/'|"|:|\.|\[|\]|\\/g,function(str){ 5 | 6 | if(str==='"'){ 7 | return '@quot;' 8 | }else if(str==="'") { 9 | return '@apos;' 10 | }else if(str===':') { 11 | return ':' 12 | }else if(str==='[') { 13 | return '[' 14 | }else if(str==='[') { 15 | return ']' 16 | }else if(str==='\\') {//自定义的 找不到 17 | return '+' 18 | }else { 19 | return '·' 20 | } 21 | }); 22 | } 23 | export const spaceAdd = str=>str&&str.replace(/\+/g,' ') 24 | export const getPathName = props=>props.location&&props.location.pathname&&props.location.pathname.substring(1); 25 | export const NbspToSpace = str=>str&&str.replace(/ /g,' ') 26 | export const formatTime = time=>{ 27 | let zh = ["日","一","二","三","四","五","六"]; 28 | let date = new Date(time*1000); 29 | return format.asString('yyyy-MM-dd hh:mm', date)+' 星期'+zh[date.getDay()] 30 | } 31 | export const getArticleInfo = detailArr=>{ 32 | let {...rest}=detailArr&&detailArr[0]?detailArr[0]:{}; 33 | /*{ 34 | content, 35 | createTime, 36 | id, 37 | img, 38 | lastModify, 39 | like, 40 | modifyCount, 41 | recommend, 42 | short, 43 | title, 44 | type, 45 | url, 46 | user, 47 | visitor, 48 | week 49 | }*/ 50 | return rest 51 | } 52 | export const OldTime = 1526625828; // 2018-05-18 14:43 星期五 53 | export const getHtml=(str,newTime)=>{ 54 | if(OldTime>newTime){ //这是曾经的文章 55 | return str? str 56 | :null 57 | }else { 58 | return str? str.replace(/@quot;|@apos;/g,function(str){ 59 | if(str==='@quot;'){ 60 | return '"' 61 | }else if(str==="@apos;") { 62 | return "'" 63 | } 64 | }) 65 | :null 66 | } 67 | } -------------------------------------------------------------------------------- /app2/src/pages/AdminDetail/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {Layout, Menu, Breadcrumb, Row, Col} from 'antd'; 3 | import {List, Avatar, Icon, Divider, Tabs, Button} from 'antd'; 4 | import {connect} from 'react-redux' 5 | import Header from '../../components/Header'; 6 | import Footer from '../../components/Footer'; 7 | import {getDetail} from '../../actions' 8 | import axios from 'axios' 9 | import marked from 'marked' 10 | import {getDetailData, getDetailUrl} from '../../contains/fontEnd' 11 | import {postAdminDetailData,postAdminDetailUrl} from '../../contains/backEnd' 12 | import {updateHtml,spaceAdd,NbspToSpace} from '../../until'; 13 | import Markeder from '../../components/Markeder'; 14 | import TopTips from '../../components/TopTips'; 15 | import {formatTime} from '../../until'; 16 | import ArticleTitle from '../../components/ArticleTitle'; 17 | 18 | var html2markdown = require('html2markdown'); 19 | var converter = require('html-to-markdown'); 20 | const {Content} = Layout; 21 | const TabPane = Tabs.TabPane; 22 | 23 | class AdminDetail extends Component { 24 | constructor() { 25 | super() 26 | } 27 | 28 | componentWillMount() { 29 | if(this.props.location.pathname==='/PostArticle')return; 30 | let adminDetailId=/AdminDetail\/(\d+)/.exec(this.props.location.pathname)[1] 31 | this.props.dispatch(getDetailData(`${getDetailUrl}?id=${adminDetailId}`)) 32 | } 33 | 34 | 35 | render() { 36 | return ( 37 |
38 | 39 | 40 |
41 | 42 | 43 |
44 |
45 |
46 |
47 | ); 48 | } 49 | } 50 | 51 | const select = (state) => { 52 | return { 53 | detail: state.detail, 54 | } 55 | } 56 | export default connect(select)(AdminDetail); 57 | -------------------------------------------------------------------------------- /koa2-router-demo/models/user.js: -------------------------------------------------------------------------------- 1 | const dbUtils = require('../utils/db_util') 2 | 3 | const user = { 4 | 5 | /** 6 | * 数据库创建用户 7 | * @param {object} model 用户数据模型 8 | * @return {object} mysql执行结果 9 | */ 10 | async create ( model ) { 11 | let result = await dbUtils.insertData( 'user_info', model ) 12 | return result 13 | }, 14 | 15 | /** 16 | * 查找一个存在用户的数据 17 | * @param {obejct} options 查找条件参数 18 | * @return {object|null} 查找结果 19 | */ 20 | async getExistOne(options) { 21 | let _sql = ` 22 | SELECT * from user_info 23 | where email="${options.email}" or name="${options.name}" 24 | limit 1` 25 | let result = await dbUtils.query( _sql ) 26 | if ( Array.isArray(result) && result.length > 0 ) { 27 | result = result[0] 28 | } else { 29 | result = null 30 | } 31 | return result 32 | }, 33 | 34 | /** 35 | * 根据用户名和密码查找用户 36 | * @param {object} options 用户名密码对象 37 | * @return {object|null} 查找结果 38 | */ 39 | async getOneByUserNameAndPassword( options ) { 40 | let _sql = ` 41 | SELECT * from user_info 42 | where password="${options.password}" and name="${options.name}" 43 | limit 1` 44 | let result = await dbUtils.query( _sql ) 45 | if ( Array.isArray(result) && result.length > 0 ) { 46 | result = result[0] 47 | } else { 48 | result = null 49 | } 50 | return result 51 | }, 52 | 53 | /** 54 | * 根据用户名查找用户信息 55 | * @param {string} userName 用户账号名称 56 | * @return {object|null} 查找结果 57 | */ 58 | async getUserInfoByUserName( userName ) { 59 | 60 | let result = await dbUtils.select( 61 | 'user_info', 62 | ['id', 'email', 'name', 'detail_info', 'create_time', 'modified_time', 'modified_time' ]) 63 | if ( Array.isArray(result) && result.length > 0 ) { 64 | result = result[0] 65 | } else { 66 | result = null 67 | } 68 | return result 69 | } 70 | } 71 | 72 | module.exports = user -------------------------------------------------------------------------------- /app2/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