diff --git a/.gitignore b/.gitignore
index 2d70b03c..e77c88ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-server/public/bundle.js
+server/public/js
server/public/index.html
node_modules/
babel_cache/
diff --git a/client/components/editor.js b/client/components/editor.js
index c73ded0f..39c969ec 100644
--- a/client/components/editor.js
+++ b/client/components/editor.js
@@ -6,7 +6,6 @@ import CodeMirror from 'codemirror/lib/codemirror';
// keybinding
import 'codemirror/keymap/emacs.js';
-
// search
import 'codemirror/addon/search/searchcursor.js';
import 'codemirror/addon/search/search.js';
diff --git a/client/components/index.js b/client/components/index.js
index de6d7238..3db3a3ef 100644
--- a/client/components/index.js
+++ b/client/components/index.js
@@ -1,4 +1,5 @@
export { BreadCrumb } from './breadcrumb';
-export { Editor } from './editor';
export { FileSystem } from './filesystem';
export { Connect } from './connect';
+// Those are commented because they will delivered as a separate chunk
+// export { Editor } from './editor';
diff --git a/client/pages/index.js b/client/pages/index.js
index aa98aa55..6fd94453 100644
--- a/client/pages/index.js
+++ b/client/pages/index.js
@@ -1,6 +1,7 @@
export { HomePage } from './homepage';
export { ConnectPage } from './connectpage';
export { LogoutPage } from './logout';
-export { FilesPage } from './filespage';
-export { ViewerPage } from './viewerpage';
export { NotFoundPage } from './notfound';
+// Those are commented because they will delivered as a separate chunk
+// export { FilesPage } from './filespage';
+// export { ViewerPage } from './viewerpage';
diff --git a/client/pages/viewerpage.js b/client/pages/viewerpage.js
index e18d1a3e..cbb766db 100644
--- a/client/pages/viewerpage.js
+++ b/client/pages/viewerpage.js
@@ -1,16 +1,26 @@
import React from 'react';
-import { BreadCrumb, Editor } from '../components/';
-import { debounce, throttle, NgIf, Loader, Error, Fab, Icon, Container } from '../utilities/';
+import { BreadCrumb } from '../components/';
+import { Bundle, debounce, NgIf, Loader, Error, Container } from '../utilities/';
import { Files, opener, EventReceiver, EventEmitter } from '../data/';
+import { AudioPlayer, FileDownloader, ImageViewer, PDFViewer } from './viewerpage/';
import Path from 'path';
-import { theme } from '../utilities';
-import WaveSurfer from 'wavesurfer.js';
-import videojs from 'video.js';
+
+
+const VideoPlayer = (props) => (
+
+ {(Comp) => }
+
+);
+const IDE = (props) => (
+
+ {(Comp) => }
+
+);
@EventReceiver
export class ViewerPage extends React.Component {
- constructor(props){
+ constructor(props){
super(props);
this.state = {
path: props.match.url.replace('/view', ''),
@@ -83,6 +93,7 @@ export class ViewerPage extends React.Component {
Files.url(this.state.path).then((url) => {
this.setState({data: url, loading: false, opener: app});
}).catch(err => {
+ console.log("ERROR", err)
if(err && err.code === 'CANCELLED'){ return }
this.setState({error: err});
});
@@ -139,285 +150,3 @@ export class ViewerPage extends React.Component {
}
}
-
-class IDE extends React.Component {
- constructor(props){
- super(props);
- this.state = {
- contentToSave: null
- }
- }
-
- onContentUpdate(text){
- this.props.needSaving(true);
- this.setState({contentToSave: text})
- }
-
- save(){
- let file, blob = new window.Blob([this.state.contentToSave], {type : 'text/plain'});
- try{
- file = new window.File([blob], 'test.txt');
- }catch(err){
- // for crappy browser:
- // https://stackoverflow.com/questions/33821631/alternative-for-file-constructor-for-safari
- file = blob;
- }
- this.props.onSave(file);
- }
-
- render(){
- return (
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-
-const ImageViewer = (props) => {
- return (
-
-
-
-

-
-
- )
-}
-
-
-const PDFViewer = (props) => {
- return (
-
-
-
- );
-}
-
-class AudioPlayer extends React.Component {
- constructor(props){
- super(props);
- this.state = {
- wafesurfer: null,
- loading: true,
- isPlaying: true,
- error: null
- }
- this.toggle = this.toggle.bind(this);
- window.addEventListener('keypress', this.toggle);
- }
-
- componentDidMount(){
- let $el = document.querySelector('.player');
- var wavesurfer = WaveSurfer.create({
- container: '#waveform',
- waveColor: '#323639',
- progressColor: '#6f6f6f',
- cursorColor: '#323639',
- cursorWidth: 2,
- height: 250,
- barWidth: 1
- });
- this.setState({wavesurfer: wavesurfer});
- wavesurfer.on('ready', () => {
- this.setState({loading: false});
- if(this.state.isPlaying === true){
- wavesurfer.play();
- }
- });
- wavesurfer.on('error', (err) => {
- this.setState({error: err, loading: false});
- });
- wavesurfer.load(this.props.data);
- }
-
- componentWillUnmount(){
- if(this.state.wavesurfer){
- this.state.wavesurfer.destroy();
- }
- window.removeEventListener('keypress', this.toggle);
- }
-
- toggle(){
- if(this.state.isPlaying === true){
- this.setState({isPlaying: false});
- this.state.wavesurfer.pause();
- }else{
- this.setState({isPlaying: true});
- this.state.wavesurfer.play();
- }
- }
-
- onPlay(e){
- e.preventDefault();
- e.stopPropagation();
- this.setState({isPlaying: true})
- this.state.wavesurfer.play();
- }
-
- onPause(e){
- e.preventDefault();
- e.stopPropagation();
- this.setState({isPlaying: false});
- this.state.wavesurfer.pause();
- }
-
- render(){
- return (
-
-
-
-
- {this.state.error}
-
-
-
-
-
-
-
-
-
- )
- }
-}
-
-class VideoPlayer extends React.Component {
- constructor(props){
- super(props);
- }
-
- componentDidMount(){
- this.player = videojs(this.videoNode, {
- //autoplay: true,
- controls: true,
- aspectRatio: '16:9',
- fluid: false,
- sources: [{
- src: this.props.data
- }]
- }, function onPlayerReady() {
- //console.log('onPlayerReady', this)
- });
- }
-
- componentWillUnmount() {
- if (this.player) {
- this.player.dispose()
- }
- }
-
- render(){
- return (
-
-
-
-
-
-
-
-
- )
- }
-}
-
-class MenuBar extends React.Component{
- constructor(props){
- super(props);
- this.state = {loading: false, id: null}
- }
-
- onDownloadRequest(){
- this.setState({
- loading: true,
- id: window.setInterval(function(){
- if(document.cookie){
- this.setState({loading: false})
- window.clearInterval(this.state.id);
- }
- }.bind(this), 80)
- })
- }
-
- componentWillUnmount(){
- window.clearInterval(this.state.id)
- }
-
-
- render(){
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- {this.props.title}
-
-
- );
- }
-}
-
-class FileDownloader extends React.Component{
- constructor(props){
- super(props)
- this.state = {loading: false, id: null};
- }
-
- onClick(){
- this.setState({
- loading: true,
- id: window.setInterval(function(){
- if(document.cookie){
- this.setState({loading: false})
- window.clearInterval(this.state.id);
- }
- }.bind(this), 80)
- });
- }
-
- componentWillUnmount(){
- window.clearInterval(this.state.id)
- }
-
- render(){
- return (
-
- );
- }
-}
diff --git a/client/pages/viewerpage/audioplayer.js b/client/pages/viewerpage/audioplayer.js
new file mode 100644
index 00000000..3d39fb14
--- /dev/null
+++ b/client/pages/viewerpage/audioplayer.js
@@ -0,0 +1,102 @@
+import React from 'react';
+import { MenuBar } from './menubar';
+import { NgIf, Icon, theme } from '../../utilities/'
+import WaveSurfer from 'wavesurfer.js';
+
+export class AudioPlayer extends React.Component {
+ constructor(props){
+ super(props);
+ this.state = {
+ wafesurfer: null,
+ loading: true,
+ isPlaying: true,
+ error: null
+ }
+ this.toggle = this.toggle.bind(this);
+ window.addEventListener('keypress', this.toggle);
+ }
+
+ componentDidMount(){
+ let $el = document.querySelector('.player');
+ var wavesurfer = WaveSurfer.create({
+ container: '#waveform',
+ waveColor: '#323639',
+ progressColor: '#6f6f6f',
+ cursorColor: '#323639',
+ cursorWidth: 2,
+ height: 250,
+ barWidth: 1
+ });
+ this.setState({wavesurfer: wavesurfer});
+ wavesurfer.on('ready', () => {
+ this.setState({loading: false});
+ if(this.state.isPlaying === true){
+ wavesurfer.play();
+ }
+ });
+ wavesurfer.on('error', (err) => {
+ this.setState({error: err, loading: false});
+ });
+ wavesurfer.load(this.props.data);
+ }
+
+ componentWillUnmount(){
+ if(this.state.wavesurfer){
+ this.state.wavesurfer.destroy();
+ }
+ window.removeEventListener('keypress', this.toggle);
+ }
+
+ toggle(){
+ if(this.state.isPlaying === true){
+ this.setState({isPlaying: false});
+ this.state.wavesurfer.pause();
+ }else{
+ this.setState({isPlaying: true});
+ this.state.wavesurfer.play();
+ }
+ }
+
+ onPlay(e){
+ e.preventDefault();
+ e.stopPropagation();
+ this.setState({isPlaying: true})
+ this.state.wavesurfer.play();
+ }
+
+ onPause(e){
+ e.preventDefault();
+ e.stopPropagation();
+ this.setState({isPlaying: false});
+ this.state.wavesurfer.pause();
+ }
+
+ render(){
+ return (
+
+
+
+
+ {this.state.error}
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
diff --git a/client/pages/viewerpage/filedownloader.js b/client/pages/viewerpage/filedownloader.js
new file mode 100644
index 00000000..54beeeb0
--- /dev/null
+++ b/client/pages/viewerpage/filedownloader.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import { MenuBar } from './menubar';
+import { theme, NgIf, Icon } from '../../utilities/'
+
+export class FileDownloader extends React.Component{
+ constructor(props){
+ super(props)
+ this.state = {loading: false, id: null};
+ }
+
+ onClick(){
+ this.setState({
+ loading: true,
+ id: window.setInterval(function(){
+ if(document.cookie){
+ this.setState({loading: false})
+ window.clearInterval(this.state.id);
+ }
+ }.bind(this), 80)
+ });
+ }
+
+ componentWillUnmount(){
+ window.clearInterval(this.state.id)
+ }
+
+ render(){
+ return (
+
+ );
+ }
+}
diff --git a/client/pages/viewerpage/ide.js b/client/pages/viewerpage/ide.js
new file mode 100644
index 00000000..0fa56000
--- /dev/null
+++ b/client/pages/viewerpage/ide.js
@@ -0,0 +1,45 @@
+import React from 'react';
+import { Editor } from '../../components/editor';
+import { NgIf, Fab, Icon } from '../../utilities/'
+import { MenuBar } from './menubar';
+
+
+export class IDE extends React.Component {
+ constructor(props){
+ super(props);
+ this.state = {
+ contentToSave: null
+ }
+ }
+
+ onContentUpdate(text){
+ this.props.needSaving(true);
+ this.setState({contentToSave: text})
+ }
+
+ save(){
+ let file, blob = new window.Blob([this.state.contentToSave], {type : 'text/plain'});
+ try{
+ file = new window.File([blob], 'test.txt');
+ }catch(err){
+ // for crappy browser:
+ // https://stackoverflow.com/questions/33821631/alternative-for-file-constructor-for-safari
+ file = blob;
+ }
+ this.props.onSave(file);
+ }
+
+ render(){
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/client/pages/viewerpage/imageviewer.js b/client/pages/viewerpage/imageviewer.js
new file mode 100644
index 00000000..ef48dcae
--- /dev/null
+++ b/client/pages/viewerpage/imageviewer.js
@@ -0,0 +1,14 @@
+import React from 'react';
+import { theme } from '../../utilities/';
+import { MenuBar } from './menubar';
+
+export const ImageViewer = (props) => {
+ return (
+
+
+
+

+
+
+ )
+}
diff --git a/client/pages/viewerpage/index.js b/client/pages/viewerpage/index.js
index ff067500..e811af77 100644
--- a/client/pages/viewerpage/index.js
+++ b/client/pages/viewerpage/index.js
@@ -1,4 +1,7 @@
-module.exports = {
- test: 'test'
-}
-
+export { AudioPlayer } from './audioplayer';
+export { FileDownloader } from './filedownloader';
+export { ImageViewer } from './imageviewer';
+export { PDFViewer } from './pdfviewer';
+// Those are commented because they will delivered as a separate chunk
+// export { VideoPlayer } from './videoplayer';
+// export { IDE } from './ide';
diff --git a/client/pages/viewerpage/menubar.js b/client/pages/viewerpage/menubar.js
new file mode 100644
index 00000000..b83145fa
--- /dev/null
+++ b/client/pages/viewerpage/menubar.js
@@ -0,0 +1,46 @@
+import React from 'react';
+import { theme, Container, NgIf, Icon } from '../../utilities/';
+
+export class MenuBar extends React.Component{
+ constructor(props){
+ super(props);
+ this.state = {loading: false, id: null}
+ }
+
+ onDownloadRequest(){
+ this.setState({
+ loading: true,
+ id: window.setInterval(function(){
+ if(document.cookie){
+ this.setState({loading: false})
+ window.clearInterval(this.state.id);
+ }
+ }.bind(this), 80)
+ })
+ }
+
+ componentWillUnmount(){
+ window.clearInterval(this.state.id)
+ }
+
+
+ render(){
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ {this.props.title}
+
+
+ );
+ }
+}
diff --git a/client/pages/viewerpage/pdfviewer.js b/client/pages/viewerpage/pdfviewer.js
new file mode 100644
index 00000000..8d1540a4
--- /dev/null
+++ b/client/pages/viewerpage/pdfviewer.js
@@ -0,0 +1,9 @@
+import React from 'react';
+
+export const PDFViewer = (props) => {
+ return (
+
+
+
+ );
+}
diff --git a/client/pages/viewerpage/videoplayer.js b/client/pages/viewerpage/videoplayer.js
new file mode 100644
index 00000000..fe86eb00
--- /dev/null
+++ b/client/pages/viewerpage/videoplayer.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import { MenuBar } from './menubar';
+import { theme } from '../../utilities/';
+import videojs from 'video.js';
+
+export class VideoPlayer extends React.Component {
+ constructor(props){
+ super(props);
+ }
+
+ componentDidMount(){
+ this.player = videojs(this.videoNode, {
+ //autoplay: true,
+ controls: true,
+ aspectRatio: '16:9',
+ fluid: false,
+ sources: [{
+ src: this.props.data
+ }]
+ }, function onPlayerReady() {
+ //console.log('onPlayerReady', this)
+ });
+ }
+
+ componentWillUnmount() {
+ if (this.player) {
+ this.player.dispose()
+ }
+ }
+
+ render(){
+ return (
+
+
+
+
+
+
+
+
+ )
+ }
+}
diff --git a/client/router.js b/client/router.js
index a705cb53..c606608d 100644
--- a/client/router.js
+++ b/client/router.js
@@ -1,24 +1,34 @@
import React from 'react'
import { BrowserRouter, Route, IndexRoute } from 'react-router-dom'
-import { NotFoundPage, ConnectPage, HomePage, FilesPage, ViewerPage, LogoutPage } from './pages/';
-import { URL_HOME, URL_FILES, URL_VIEWER, URL_LOGIN, URL_LOGOUT } from './utilities/';
+import { NotFoundPage, ConnectPage, HomePage, LogoutPage } from './pages/';
+import { Bundle, URL_HOME, URL_FILES, URL_VIEWER, URL_LOGIN, URL_LOGOUT } from './utilities/';
import { createBrowserHistory } from 'history'
+const FilesPage = (props) => (
+
+ {(Comp) => }
+
+);
+const ViewerPage = (props) => (
+
+ {(Comp) => }
+
+);
export default class AppRouter extends React.Component {
- render() {
- return (
-
-
-
-
-
-
-
-
-
- );
- }
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ }
}
diff --git a/client/utilities/bundle.js b/client/utilities/bundle.js
new file mode 100644
index 00000000..90c45476
--- /dev/null
+++ b/client/utilities/bundle.js
@@ -0,0 +1,42 @@
+// taken from https://reacttraining.com/react-router/web/guides/code-splitting
+import React from 'react';
+import Path from 'path';
+
+export class Bundle extends React.Component {
+ state = { mod: null };
+
+ componentWillMount() {
+ this.load(this.props)
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if(nextProps.load !== this.props.load){ this.load(nextProps) }
+ }
+
+ load(props) {
+ this.setState({
+ mod: null
+ });
+ props.loader
+ .then((_mod) => {
+ this.setState({
+ mod: function(mod){
+ if(mod['default']){
+ return mod.default;
+ }else if(mod['__esModule'] === true){
+ return mod[props.symbol] ? mod[props.symbol] : null;
+ }else{
+ return mod;
+ }
+ }(_mod)
+ })
+ })
+ .catch((err) => {
+ console.warn(err)
+ })
+ }
+
+ render() {
+ return this.state.mod ? this.props.children(this.state.mod) : null
+ }
+}
diff --git a/client/utilities/index.js b/client/utilities/index.js
index 5b7b1ae4..b34cde5d 100644
--- a/client/utilities/index.js
+++ b/client/utilities/index.js
@@ -16,3 +16,4 @@ export { Uploader } from './uploader';
export { theme, to_rgba } from './theme';
export { encrypt, decrypt } from './crypto'
export { pathBuilder } from './path';
+export { Bundle } from './bundle';
diff --git a/docker/img/Dockerfile b/docker/img/Dockerfile
index 61950330..10a582a3 100644
--- a/docker/img/Dockerfile
+++ b/docker/img/Dockerfile
@@ -6,13 +6,14 @@ WORKDIR "/app"
RUN cd /app/ && \
# remove dev stuff
- npm run clean && \
+ npm run clear && \
# build
apt-get update -y && \
apt install -y libssl-dev build-essential automake python libcurl3-dev && \
npm install nodegit --build-from-source && \
npm install && \
npm run build && \
+ # prepare for production
npm prune --production && \
apt-get -y clean && \
apt-get -y purge --auto-remove build-essential automake python && \
diff --git a/package.json b/package.json
index 980bde2c..d43a9319 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,8 @@
"publish": "docker tag nuage machines/nuage && docker push machines/nuage",
"start": "cd docker && docker-compose up -d",
"stop": "cd docker && docker-compose down",
- "clean": "rm -rf node_modules server/public/bundle.js server/public/index.html || true"
+ "clean": "rm -rf server/public/js server/public/*.html || true",
+ "clear": "npm run clean && rm -rf node_modules"
},
"author": "",
"license": "ISC",
@@ -72,6 +73,7 @@
"html-webpack-plugin": "^2.28.0",
"http-server": "^0.9.0",
"nodemon": "^1.11.0",
+ "webpack-bundle-analyzer": "^2.8.2",
"webpack-dev-server": "^2.4.5"
}
}
diff --git a/webpack.config.js b/webpack.config.js
index d9156ff3..7f95242e 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,22 +1,25 @@
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
+const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
let config = {
- entry: [
- 'babel-polyfill',
- path.join(__dirname, 'client', 'index.js')
- ],
+ entry: {
+ polyfill: 'babel-polyfill',
+ app: path.join(__dirname, 'client', 'index.js')
+ },
output: {
path: path.join(__dirname, 'server', 'public'),
publicPath: '/',
- filename: 'bundle.js'
+ filename: 'js/[name].js',
+ chunkFilename: "js/chunk.[name].[id].js"
},
module: {
loaders: [
{
test: path.join(__dirname, 'client'),
- loader: ['babel-loader']
+ loader: ['babel-loader'],
+ exclude: /node_modules/
},
{
test: /\.html$/,
@@ -32,7 +35,8 @@ let config = {
new HtmlWebpackPlugin({
template: path.join(__dirname, 'client', 'index.html'),
inject:true
- })
+ }),
+ new webpack.optimize.CommonsChunkPlugin({name: "polyfill", filename: "js/polyfill.js"}),
]
};
@@ -59,5 +63,6 @@ if(process.env.NODE_ENV === 'production'){
}
+//config.plugins.push(new BundleAnalyzerPlugin())
module.exports = config;