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 +
|
||||
+ Basic REST API +
|
||||
+ Basic Layout +
|
||||
- React Components
|
||||
- Wire React to ES API
|
||||
- Simple CRUID interface
|
||||
- Orchestrate Environment Configs
|
||||
- ElasticSearch Schema
|
||||
- Reader Layout
|
||||
- Bootstrap / React with Bower
|
||||
- Basic Testing
|
||||
- Front-End Dependency Manager
|
||||
|
||||
- v0.2 Chapter CRUD
|
||||
- Chapter Manage Component with Create and Delete Options
|
||||
- Edit Chapter Component with Delete
|
||||
- v0.2 Reader
|
||||
- Reader UX
|
||||
- Top Bar
|
||||
- Background Texture - Canvas / Paper
|
||||
|
||||
- v0.3 Notes
|
||||
- v0.3 Notes and Text Formatting
|
||||
- Abstract API Blueprint for Notes
|
||||
- Note Manager Component
|
||||
|
||||
- Error Handling
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
from flask import Flask
|
||||
from flask_webpack import Webpack
|
||||
from werkzeug.serving import run_simple
|
||||
|
||||
from blueprints.reader import reader
|
||||
from blueprints.api import api
|
||||
|
||||
# Initialize application
|
||||
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
|
||||
application.register_blueprint(reader)
|
||||
application.register_blueprint(api, url_prefix='/api')
|
||||
|
||||
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 jinja2 import TemplateNotFound
|
||||
from elasticsearch import Elasticsearch
|
||||
|
||||
#Elasticsearch local connection
|
||||
#TODO: Extract to config
|
||||
ELASTICSEARCH_HOST = '127.0.0.1:9200'
|
||||
es = Elasticsearch(ELASTICSEARCH_HOST)
|
||||
# if es.ping() == True?
|
||||
|
||||
print 'API initialized!'
|
||||
|
||||
api = Blueprint('api', __name__)
|
||||
|
||||
# Get all chapters
|
||||
@api.route('/chapters')
|
||||
@api.route('/chapters/')
|
||||
def get_chapters():
|
||||
res = es.search(index='joyce', doc_type='chapters', body={'query': {'match_all': {}}})
|
||||
# chapters = { your_key: old_dict[your_key] for your_key in your_keys }
|
||||
search = es.search(index='joyce', doc_type='chapters', body={'query': {'match_all': {}}})
|
||||
res = []
|
||||
for x in search['hits']['hits']:
|
||||
res.append(x['_source'])
|
||||
return jsonify(res)
|
||||
|
||||
# Get singular chapter
|
||||
# Get specific chapter
|
||||
@api.route('/chapters/<int:id>')
|
||||
def get_chapter(id):
|
||||
res = es.get(index='joyce', doc_type='chapters', id=id, _source=True)
|
||||
return jsonify(res['_source'])
|
||||
res = es.get_source(index='joyce', doc_type='chapters', id=id, _source=True)
|
||||
return jsonify(res)
|
||||
|
||||
# Create and update chapters
|
||||
@api.route('/chapters/<int:id>', methods=['POST', 'PUT'])
|
||||
|
|
|
@ -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
|
||||
Flask==0.12.2
|
||||
Flask-Bootstrap==3.3.7.1
|
||||
Flask-Webpack==0.1.0
|
||||
itsdangerous==0.24
|
||||
Jinja2==2.9.6
|
||||
macholib==1.5.1
|
||||
|
|
|
@ -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')
|
||||
)
|
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -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");
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
{"assets":{"app.js":"app.2803b3dead751fb6d8e3.js"},"publicPath":"static/js/"}
|
|
@ -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>
|
|
@ -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