Adding NPM, Babel, Webpack for basic React front end
This commit is contained in:
parent
cfbaf067ed
commit
a1748b7220
21
TODO.txt
21
TODO.txt
|
@ -1,16 +1,21 @@
|
||||||
- v0.1 Basic Reader
|
- v0.1 Text Editor + Basic Reader
|
||||||
+ Flask Microservice +
|
+ Flask Microservice +
|
||||||
+ Basic REST API +
|
+ Basic REST API +
|
||||||
|
+ Basic Layout +
|
||||||
|
- React Components
|
||||||
|
- Wire React to ES API
|
||||||
|
- Simple CRUID interface
|
||||||
- Orchestrate Environment Configs
|
- Orchestrate Environment Configs
|
||||||
- ElasticSearch Schema
|
- Basic Testing
|
||||||
- Reader Layout
|
- Front-End Dependency Manager
|
||||||
- Bootstrap / React with Bower
|
|
||||||
|
|
||||||
- v0.2 Chapter CRUD
|
- v0.2 Reader
|
||||||
- Chapter Manage Component with Create and Delete Options
|
- Reader UX
|
||||||
- Edit Chapter Component with Delete
|
- Top Bar
|
||||||
|
- Background Texture - Canvas / Paper
|
||||||
|
|
||||||
- v0.3 Notes
|
- v0.3 Notes and Text Formatting
|
||||||
|
- Abstract API Blueprint for Notes
|
||||||
- Note Manager Component
|
- Note Manager Component
|
||||||
|
|
||||||
- Error Handling
|
- Error Handling
|
||||||
|
|
|
@ -1,13 +1,27 @@
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
from flask_webpack import Webpack
|
||||||
|
from werkzeug.serving import run_simple
|
||||||
|
|
||||||
from blueprints.reader import reader
|
from blueprints.reader import reader
|
||||||
from blueprints.api import api
|
from blueprints.api import api
|
||||||
|
|
||||||
# Initialize application
|
# Initialize application
|
||||||
application = Flask(__name__)
|
application = Flask(__name__)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'DEBUG': True,
|
||||||
|
'WEBPACK_MANIFEST_PATH': './static/js/manifest.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
application.config.update(params)
|
||||||
|
|
||||||
|
webpack = Webpack()
|
||||||
|
webpack.init_app(application)
|
||||||
|
|
||||||
# Register blueprints
|
# Register blueprints
|
||||||
application.register_blueprint(reader)
|
application.register_blueprint(reader)
|
||||||
application.register_blueprint(api, url_prefix='/api')
|
application.register_blueprint(api, url_prefix='/api')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
application.run()
|
# application.debug=True
|
||||||
|
run_simple('localhost', 5000, application, use_reloader=True, use_debugger=True)
|
|
@ -1,26 +1,30 @@
|
||||||
from flask import Blueprint, render_template, abort, jsonify, request
|
from flask import Blueprint, render_template, abort, jsonify, request
|
||||||
from jinja2 import TemplateNotFound
|
|
||||||
from elasticsearch import Elasticsearch
|
from elasticsearch import Elasticsearch
|
||||||
|
|
||||||
#Elasticsearch local connection
|
#Elasticsearch local connection
|
||||||
#TODO: Extract to config
|
#TODO: Extract to config
|
||||||
ELASTICSEARCH_HOST = '127.0.0.1:9200'
|
ELASTICSEARCH_HOST = '127.0.0.1:9200'
|
||||||
es = Elasticsearch(ELASTICSEARCH_HOST)
|
es = Elasticsearch(ELASTICSEARCH_HOST)
|
||||||
|
# if es.ping() == True?
|
||||||
|
|
||||||
|
print 'API initialized!'
|
||||||
|
|
||||||
api = Blueprint('api', __name__)
|
api = Blueprint('api', __name__)
|
||||||
|
|
||||||
# Get all chapters
|
# Get all chapters
|
||||||
@api.route('/chapters')
|
@api.route('/chapters/')
|
||||||
def get_chapters():
|
def get_chapters():
|
||||||
res = es.search(index='joyce', doc_type='chapters', body={'query': {'match_all': {}}})
|
search = es.search(index='joyce', doc_type='chapters', body={'query': {'match_all': {}}})
|
||||||
# chapters = { your_key: old_dict[your_key] for your_key in your_keys }
|
res = []
|
||||||
|
for x in search['hits']['hits']:
|
||||||
|
res.append(x['_source'])
|
||||||
return jsonify(res)
|
return jsonify(res)
|
||||||
|
|
||||||
# Get singular chapter
|
# Get specific chapter
|
||||||
@api.route('/chapters/<int:id>')
|
@api.route('/chapters/<int:id>')
|
||||||
def get_chapter(id):
|
def get_chapter(id):
|
||||||
res = es.get(index='joyce', doc_type='chapters', id=id, _source=True)
|
res = es.get_source(index='joyce', doc_type='chapters', id=id, _source=True)
|
||||||
return jsonify(res['_source'])
|
return jsonify(res)
|
||||||
|
|
||||||
# Create and update chapters
|
# Create and update chapters
|
||||||
@api.route('/chapters/<int:id>', methods=['POST', 'PUT'])
|
@api.route('/chapters/<int:id>', methods=['POST', 'PUT'])
|
||||||
|
|
0
blueprints/editor.py
Normal file
0
blueprints/editor.py
Normal file
30
package.json
Normal file
30
package.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "joyce",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Reader and Editor for Hypertext",
|
||||||
|
"main": "app.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack-dev-server --progress --colors --port 2992 --content-base static/js",
|
||||||
|
"build": "webpack --config webpack.config.js --watch",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "Alex Hunt",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^16.0.0",
|
||||||
|
"react-dom": "^16.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.26.0",
|
||||||
|
"babel-loader": "^7.1.2",
|
||||||
|
"babel-preset-env": "^1.6.1",
|
||||||
|
"babel-preset-react": "^6.24.1",
|
||||||
|
"clean-webpack-plugin": "^0.1.17",
|
||||||
|
"html-webpack-plugin": "^2.30.1",
|
||||||
|
"manifest-revision-webpack-plugin": "^0.4.1",
|
||||||
|
"sync-exec": "^0.6.2",
|
||||||
|
"webpack": "^3.8.1",
|
||||||
|
"webpack-dev-server": "^2.9.3",
|
||||||
|
"webpack-manifest-plugin": "^1.3.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ dominate==2.3.1
|
||||||
elasticsearch==5.4.0
|
elasticsearch==5.4.0
|
||||||
Flask==0.12.2
|
Flask==0.12.2
|
||||||
Flask-Bootstrap==3.3.7.1
|
Flask-Bootstrap==3.3.7.1
|
||||||
|
Flask-Webpack==0.1.0
|
||||||
itsdangerous==0.24
|
itsdangerous==0.24
|
||||||
Jinja2==2.9.6
|
Jinja2==2.9.6
|
||||||
macholib==1.5.1
|
macholib==1.5.1
|
||||||
|
|
48
src/app.js
Normal file
48
src/app.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
class ChapterButton extends React.Component {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ChapterList extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
chapters: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const chapters = axios.get('/api/chapters').then(res => {
|
||||||
|
const chapters = res.data.sort((a, b) => a.id - b.id)
|
||||||
|
return chapters
|
||||||
|
}).catch(error =>
|
||||||
|
console.log(error)
|
||||||
|
).then(chapters => this.setState({chapters}))
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div id="highlight_button" className="text-center">
|
||||||
|
<a href="#" className="btn btn-primary btn-lg">Highlight Notes</a>
|
||||||
|
</div>
|
||||||
|
{console.log(this.state.chapters)}
|
||||||
|
{this.state.chapters.map(chapter =>
|
||||||
|
<div>
|
||||||
|
<a className='btn btn-primary btn-lg' href={chapter.id}>{chapter.name}</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<ChapterList chapter='Telemachus'/>,
|
||||||
|
document.getElementById('sidebar')
|
||||||
|
)
|
BIN
static/.DS_Store
vendored
Normal file
BIN
static/.DS_Store
vendored
Normal file
Binary file not shown.
11141
static/js/app.099f0241e41334b336cb.js
Normal file
11141
static/js/app.099f0241e41334b336cb.js
Normal file
File diff suppressed because one or more lines are too long
11141
static/js/app.11dd4bc8bcb22a9fc0c0.js
Normal file
11141
static/js/app.11dd4bc8bcb22a9fc0c0.js
Normal file
File diff suppressed because one or more lines are too long
11139
static/js/app.159bd6f0bc0e811c9faf.js
Normal file
11139
static/js/app.159bd6f0bc0e811c9faf.js
Normal file
File diff suppressed because one or more lines are too long
11148
static/js/app.17b8ee2ad1c37caeb90e.js
Normal file
11148
static/js/app.17b8ee2ad1c37caeb90e.js
Normal file
File diff suppressed because one or more lines are too long
11150
static/js/app.2803b3dead751fb6d8e3.js
Normal file
11150
static/js/app.2803b3dead751fb6d8e3.js
Normal file
File diff suppressed because one or more lines are too long
11141
static/js/app.293705c65c0de83a548c.js
Normal file
11141
static/js/app.293705c65c0de83a548c.js
Normal file
File diff suppressed because one or more lines are too long
11149
static/js/app.4950aab02cedc0752ead.js
Normal file
11149
static/js/app.4950aab02cedc0752ead.js
Normal file
File diff suppressed because one or more lines are too long
11141
static/js/app.52b659d6ebb1f2bf0230.js
Normal file
11141
static/js/app.52b659d6ebb1f2bf0230.js
Normal file
File diff suppressed because one or more lines are too long
11148
static/js/app.65861df4479673f45802.js
Normal file
11148
static/js/app.65861df4479673f45802.js
Normal file
File diff suppressed because one or more lines are too long
11140
static/js/app.66823f4251da5ae61fec.js
Normal file
11140
static/js/app.66823f4251da5ae61fec.js
Normal file
File diff suppressed because one or more lines are too long
11147
static/js/app.74858d1abf63ce037930.js
Normal file
11147
static/js/app.74858d1abf63ce037930.js
Normal file
File diff suppressed because one or more lines are too long
84
static/js/app.76368f0b538caa154430.js
Normal file
84
static/js/app.76368f0b538caa154430.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/******/ (function(modules) { // webpackBootstrap
|
||||||
|
/******/ // The module cache
|
||||||
|
/******/ var installedModules = {};
|
||||||
|
/******/
|
||||||
|
/******/ // The require function
|
||||||
|
/******/ function __webpack_require__(moduleId) {
|
||||||
|
/******/
|
||||||
|
/******/ // Check if module is in cache
|
||||||
|
/******/ if(installedModules[moduleId]) {
|
||||||
|
/******/ return installedModules[moduleId].exports;
|
||||||
|
/******/ }
|
||||||
|
/******/ // Create a new module (and put it into the cache)
|
||||||
|
/******/ var module = installedModules[moduleId] = {
|
||||||
|
/******/ i: moduleId,
|
||||||
|
/******/ l: false,
|
||||||
|
/******/ exports: {}
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Execute the module function
|
||||||
|
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||||
|
/******/
|
||||||
|
/******/ // Flag the module as loaded
|
||||||
|
/******/ module.l = true;
|
||||||
|
/******/
|
||||||
|
/******/ // Return the exports of the module
|
||||||
|
/******/ return module.exports;
|
||||||
|
/******/ }
|
||||||
|
/******/
|
||||||
|
/******/
|
||||||
|
/******/ // expose the modules object (__webpack_modules__)
|
||||||
|
/******/ __webpack_require__.m = modules;
|
||||||
|
/******/
|
||||||
|
/******/ // expose the module cache
|
||||||
|
/******/ __webpack_require__.c = installedModules;
|
||||||
|
/******/
|
||||||
|
/******/ // define getter function for harmony exports
|
||||||
|
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||||
|
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||||
|
/******/ Object.defineProperty(exports, name, {
|
||||||
|
/******/ configurable: false,
|
||||||
|
/******/ enumerable: true,
|
||||||
|
/******/ get: getter
|
||||||
|
/******/ });
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||||
|
/******/ __webpack_require__.n = function(module) {
|
||||||
|
/******/ var getter = module && module.__esModule ?
|
||||||
|
/******/ function getDefault() { return module['default']; } :
|
||||||
|
/******/ function getModuleExports() { return module; };
|
||||||
|
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||||
|
/******/ return getter;
|
||||||
|
/******/ };
|
||||||
|
/******/
|
||||||
|
/******/ // Object.prototype.hasOwnProperty.call
|
||||||
|
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||||
|
/******/
|
||||||
|
/******/ // __webpack_public_path__
|
||||||
|
/******/ __webpack_require__.p = "static/js/";
|
||||||
|
/******/
|
||||||
|
/******/ // Load entry module and return exports
|
||||||
|
/******/ return __webpack_require__(__webpack_require__.s = 22);
|
||||||
|
/******/ })
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ ({
|
||||||
|
|
||||||
|
/***/ 22:
|
||||||
|
/***/ (function(module, exports, __webpack_require__) {
|
||||||
|
|
||||||
|
module.exports = __webpack_require__(23);
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 23:
|
||||||
|
/***/ (function(module, exports) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
throw new Error("Module build failed: SyntaxError: Unexpected token (26:27)\n\n\u001b[0m \u001b[90m 24 | \u001b[39m\n \u001b[90m 25 | \u001b[39m\tcomponentDidMount() {\n\u001b[31m\u001b[1m>\u001b[22m\u001b[39m\u001b[90m 26 | \u001b[39m\t\t\u001b[36mconst\u001b[39m chapters\u001b[33m:\u001b[39m axios\u001b[33m.\u001b[39mget(\u001b[32m'/api/chapters'\u001b[39m)\u001b[33m.\u001b[39mthen(res \u001b[33m=>\u001b[39m {\n \u001b[90m | \u001b[39m\t\t \u001b[31m\u001b[1m^\u001b[22m\u001b[39m\n \u001b[90m 27 | \u001b[39m\t\t\t\u001b[36mconst\u001b[39m chapters \u001b[33m=\u001b[39m res\u001b[33m.\u001b[39mdata\u001b[33m.\u001b[39msort((a\u001b[33m,\u001b[39m b) \u001b[33m=>\u001b[39m a\u001b[33m.\u001b[39mid \u001b[33m-\u001b[39m b\u001b[33m.\u001b[39mid)\n \u001b[90m 28 | \u001b[39m\t\t\t\u001b[90m// console.log(chapters)\u001b[39m\n \u001b[90m 29 | \u001b[39m\t\t\t\u001b[36mreturn\u001b[39m chapters\u001b[0m\n");
|
||||||
|
|
||||||
|
/***/ })
|
||||||
|
|
||||||
|
/******/ });
|
11149
static/js/app.bbba87bb60990d42be94.js
Normal file
11149
static/js/app.bbba87bb60990d42be94.js
Normal file
File diff suppressed because one or more lines are too long
11149
static/js/app.d310cad8a4a25512f7b3.js
Normal file
11149
static/js/app.d310cad8a4a25512f7b3.js
Normal file
File diff suppressed because one or more lines are too long
11138
static/js/app.e20772334f62f0a7d23d.js
Normal file
11138
static/js/app.e20772334f62f0a7d23d.js
Normal file
File diff suppressed because one or more lines are too long
11152
static/js/app.ea6106e1c82e4bf529d2.js
Normal file
11152
static/js/app.ea6106e1c82e4bf529d2.js
Normal file
File diff suppressed because one or more lines are too long
11148
static/js/app.f3e85294b26d871aa89a.js
Normal file
11148
static/js/app.f3e85294b26d871aa89a.js
Normal file
File diff suppressed because one or more lines are too long
1
static/js/manifest.json
Normal file
1
static/js/manifest.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"assets":{"app.js":"app.2803b3dead751fb6d8e3.js"},"publicPath":"static/js/"}
|
28
static/style.css
Normal file
28
static/style.css
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
html body {
|
||||||
|
background-color: rgba(211,211,211,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#joyce_reader {
|
||||||
|
width: 95%;
|
||||||
|
margin-top: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
background-color: rgba(250,250,250,.8);
|
||||||
|
min-height: 300px;
|
||||||
|
padding: 2%;
|
||||||
|
border: 1px solid rgba(120,120,120,.6);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#reader {
|
||||||
|
background-color: rgba(250,250,250,.8);
|
||||||
|
min-height: 700px;
|
||||||
|
padding: 2%;
|
||||||
|
border: 1px solid rgba(120,120,120,.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#highlight_button {
|
||||||
|
padding: 5% 0 5% 0;
|
||||||
|
border-bottom: 2px solid rgba(40,40,40,.5);
|
||||||
|
}
|
|
@ -1 +1,34 @@
|
||||||
<p>Hello world!</p>
|
<!doctype html>
|
||||||
|
<head>
|
||||||
|
<title>Joyce</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||||
|
<link rel="manifest" href="static/js/manifest.json">
|
||||||
|
|
||||||
|
<!-- TODO: Swap CDN Links for Bower / Yarn -->
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Reader Layout -->
|
||||||
|
<div id="joyce_reader" class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-2" id="sidebar">
|
||||||
|
<div id="highlight_button" class="text-center">
|
||||||
|
<a href="#" class="btn btn-primary btn-lg">Highlight Notes</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
List of Chapters!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-6" id="reader">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="{{asset_url_for('app.js')}}"></script>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
|
||||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
47
webpack.config.js
Normal file
47
webpack.config.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const CleanWebpackPlugin = require('clean-webpack-plugin')
|
||||||
|
const ManifestRevisionPlugin = require('manifest-revision-webpack-plugin');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const rootAssetPath = './src/';
|
||||||
|
|
||||||
|
let pathsToClean = [
|
||||||
|
'static/js/'
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: {
|
||||||
|
app: [
|
||||||
|
rootAssetPath + 'app'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
publicPath: "static/js/",
|
||||||
|
filename: 'app.[chunkhash].js',
|
||||||
|
path: path.resolve(__dirname, 'static/js')
|
||||||
|
},
|
||||||
|
watch: true,
|
||||||
|
watchOptions: {
|
||||||
|
poll: true,
|
||||||
|
ignored: /node_modules/
|
||||||
|
},
|
||||||
|
module : {
|
||||||
|
rules: [{
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
presets: ['env', 'react']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// TODO: Dev / Prod Config
|
||||||
|
// new webpack.optimize.UglifyJsPlugin(),
|
||||||
|
new ManifestRevisionPlugin(path.join('static/js', 'manifest.json'), {
|
||||||
|
rootAssetPath: rootAssetPath
|
||||||
|
}),
|
||||||
|
new CleanWebpackPlugin(pathsToClean)
|
||||||
|
],
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user