Code Restructuring

This commit is contained in:
LordMathis 2017-07-15 16:52:09 +02:00
parent e6b71ebc34
commit 7cfb6e330f
23 changed files with 401 additions and 3129 deletions

View File

@ -1,6 +1,17 @@
{ {
"presets":[ "presets":[
"es2015", "es2015", "react"
"react" ],
] "env": {
"development": {
"presets": ["es2015", "react", "stage-0"],
"plugins": ["transform-runtime"],
"presets": ["react-hmre"]
}
},
"env": {
"build": {
"presets": ["es2015", "react", "stage-0"]
}
}
} }

39
.gitignore vendored
View File

@ -1,37 +1,4 @@
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules node_modules
jspm_packages dist
public
# Optional npm cache directory *.log
.npm
# Optional REPL history
.node_repl_history

View File

@ -4,11 +4,9 @@
"description": "portfolio", "description": "portfolio",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "npm run build && babel-node src/server.js", "build": "NODE_ENV=production babel src --out-dir dist --copy-files && webpack -p --progress --config webpack.config.js",
"start:dev": "export NODE_ENV=development && npm run build:dev && nodemon --exec babel-node -- src/server.js", "start": "NODE_ENV=production node ./src/server.js",
"build": "NODE_ENV=production webpack -p", "dev": "NODE_ENV=development babel-node ./src/server.js --presets es2015,stage-2 ./srcserver.js"
"build:dev": "webpack -d",
"build:dev:watch": "webpack -d --watch"
}, },
"keywords": [ "keywords": [
"porfolio", "porfolio",
@ -17,27 +15,34 @@
"author": "Matúš Námešný", "author": "Matúš Námešný",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"ejs": "^2.5.6", "babel-cli": "^6.24.1",
"express": "^4.15.2", "babel-polyfill": "^6.7.4",
"react": "^15.4.2", "babel-runtime": "^6.6.1",
"react-dom": "^15.4.2", "express": "^4.13.4",
"react-router-dom": "^4.0.0" "isomorphic-fetch": "^2.2.1",
"react": "^15.0.1",
"react-dom": "^15.0.1",
"react-redux": "^4.4.4",
"react-router-dom": "^4.1.1"
}, },
"devDependencies": { "devDependencies": {
"babel-core": "^6.24.0", "babel-core": "^6.7.6",
"babel-loader": "^6.4.1", "babel-jest": "*",
"babel-preset-es2015": "^6.24.0", "babel-loader": "^6.2.4",
"babel-preset-react": "^6.23.0", "babel-plugin-transform-runtime": "^6.7.5",
"css-loader": "^0.28.0", "babel-preset-es2015": "^6.6.0",
"file-loader": "^0.11.1", "babel-preset-react": "^6.5.0",
"html-webpack-plugin": "^2.28.0", "babel-preset-react-hmre": "^1.1.1",
"json-loader": "^0.5.4", "babel-preset-stage-0": "^6.5.0",
"node-sass": "^4.5.2", "babel-register": "^6.7.2",
"nodemon": "^1.11.0", "css-loader": "^0.28.4",
"sass-loader": "^6.0.3", "css-modules-require-hook": "^4.0.6",
"style-loader": "^0.16.1", "extract-text-webpack-plugin": "^2.1.2",
"url-loader": "^0.5.8", "sass-loader": "^6.0.6",
"webpack": "^2.3.2", "style-loader": "^0.18.2",
"webpack-dev-server": "^2.4.2" "url-loader": "^0.5.9",
"webpack": "^2.5.1",
"webpack-dev-middleware": "^1.10.2",
"webpack-hot-middleware": "^2.18.0"
} }
} }

View File

@ -13,6 +13,6 @@ const AppClient = () => (
window.onload = () => { window.onload = () => {
render( render(
<AppClient />, <AppClient />,
document.getElementById('app') document.getElementById('root')
); );
}; };

View File

@ -1,9 +1,14 @@
import React, {Component} from 'react'; import React from 'react';
// import { Home } from '.';
export const About = () => ( export const About = () => (
<div>
<div className="content"> <div className="content">
<h1>About</h1> <h1>About</h1>
</div> </div>
</div>
); );
export default About; export default About;
// <Home key={'home'} fullwidth={false} />

View File

@ -2,15 +2,14 @@ import React from 'react';
import { Route, Switch } from 'react-router-dom'; import { Route, Switch } from 'react-router-dom';
import { Home, About, Blog, Portfolio, Resume, NotFoundPage } from '.'; import { Home, About, Blog, Portfolio, Resume, NotFoundPage } from '.';
export const App = () => ( export const App = () => (
<div> <div>
<Route component={Home} /> <Route component={Home} />
<Switch> <Switch>
<Route exact path='/about' component={About} /> <Route exact path="/about" component={About} />
<Route exact path='/blog' component={Blog} /> <Route exact path="/blog" component={Blog} />
<Route exact path='/portfolio' component={Portfolio} /> <Route exact path="/portfolio" component={Portfolio} />
<Route exact path='/resume' component={Resume} /> <Route exact path="/resume" component={Resume} />
<Route component={NotFoundPage} /> <Route component={NotFoundPage} />
</Switch> </Switch>
</div> </div>

View File

@ -1,12 +1,11 @@
import React, {Component} from 'react'; import React from 'react';
export default class Blog extends Component { export const Blog = () => (
<div>
render () {
return (
<div className="content"> <div className="content">
<h1>Hello</h1> <h1>Hello</h1>
</div> </div>
) </div>
} );
}
export default Blog;

View File

@ -1,43 +1,66 @@
import React, {Component, PropTypes} from 'react'; import React, { Component } from 'react';
import config from '../config/config.json';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import config from '../static/config/config.json';
export default class Home extends Component { export default class Home extends Component {
render() { render() {
var socialLinks = []; let key = 0;
var key = 0; const objKeys = Object.keys(config.social);
for (var i in config.social) {
socialLinks.push( const socialLinks = objKeys.map((val) => {
<a key={key} href={config.social[i]}> const link = (
<i className={"fa fa-" + i + " fa-3x"}></i> <a key={key} href={config.social[val]}>
<i className={`fa fa-${val} fa-3x`} aria-hidden="true" />
<span className="sr-only">{val}</span>
</a> </a>
); );
key++; key += 1;
}; return link;
});
socialLinks.push( socialLinks.push(
<a key={key} href={"mailto:" + config.email}><i className="fa fa-envelope-o fa-3x" aria-hidden="true"></i></a> <a key={key} href={`mailto:${config.email}`}>
) <i className="fa fa-envelope-o fa-3x" aria-hidden="true" />
<span className="sr-only">e-mail</span>
</a>,
);
return ( return (
<div id="cover-page" className={this.props.location.pathname == '/' ? "cover-page-full" : "cover-page-collapsed"}> <div id="cover-page" className={this.props.location.pathname === '/' ? 'cover-page-full' : 'cover-page-collapsed'}>
<div id="cover-page-content"> <div id="cover-page-content">
<div> <div>
<h1 id="cover-page-name"><Link to='/'>{ config.name }</Link></h1> <h1 id="cover-page-name"><Link to="/">{ config.name }</Link></h1>
</div> </div>
<div className="social"> <div className="social">
{socialLinks} {socialLinks}
</div> </div>
<div className="menu-links"> <div className="menu-links">
<ul> <ul>
<li><Link to='/about'><i className="fa fa-question" aria-hidden="true"></i> About</Link></li> <li>
<li><Link to='/blog'><i className="fa fa-rss" aria-hidden="true"></i> Blog</Link></li> <Link to="/about">
<li><Link to='/portfolio'><i className="fa fa-briefcase" aria-hidden="true"></i> Portfolio</Link></li> <i className="fa fa-question" aria-hidden="true" /> About
<li><Link to='/resume'><i className="fa fa-file-text-o" aria-hidden="true"></i> Resume</Link></li> </Link>
</li>
<li>
<Link to="/blog">
<i className="fa fa-rss" aria-hidden="true" /> Blog
</Link>
</li>
<li>
<Link to="/portfolio">
<i className="fa fa-briefcase" aria-hidden="true" /> Portfolio
</Link>
</li>
<li>
<Link to="/resume">
<i className="fa fa-file-text-o" aria-hidden="true" /> Resume
</Link>
</li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
) );
} }
} }

8
src/components/Main.js Normal file
View File

@ -0,0 +1,8 @@
import React from 'react';
import { Home } from '.';
export const Main = () => (
<Home key={'home'} fullwidth />
);
export default Main;

View File

@ -1,23 +1,18 @@
import React from 'react'; import React from 'react';
import { Link } from 'react-router-dom';
export class NotFoundPage extends React.Component { export const NotFoundPage = (props) => {
componentWillMount() { if (props.location.pathname === '/') {
const { staticContext } = this.props; return null;
if (staticContext) {
staticContext.is404 = true;
} }
}
render() {
return ( return (
<div>
<div className="content"> <div className="content">
<h1>Uhm... WHAT?</h1> <h1>Uhm... WHAT?</h1>
<h2>Looks like you're lost</h2> <h2>Looks like you&apos;re lost</h2>
<p>404 Page not found</p> <p>404 Page not found</p>
</div> </div>
</div>
); );
} };
}
export default NotFoundPage; export default NotFoundPage;

View File

@ -1,11 +1,11 @@
import React, {Component} from 'react'; import React from 'react';
export default class Portfolio extends Component{ export const Portfolio = () => (
render() { <div>
return (
<div className="content"> <div className="content">
<h1>Portfolio</h1> <h1>Portfolio</h1>
</div> </div>
</div>
); );
}
} export default Portfolio;

47
src/components/Post.js Normal file
View File

@ -0,0 +1,47 @@
import React, {Component} from 'react';
import jsonfile from 'jsonfile';
export default class Post extends Component {
static blogPost;
constructor() {
super();
var dataPath = path.join(process.cwd(), 'src/helpers/data.json');
jsonfile.readFile(dataPath, function(err, data) {
if (err) throw err;
for (var i = 0; i < data.posts.length; i++) {
var val = data.posts[i];
if (val.filename === this.props.match.params.post) {
blogPost = val;
}
}
}.bind(this));
}
render () {
return (
<div className="content">
<div className="post-header">
<h1>
{blogPost.title}
</h1>
<span>
{blogPost.published}
</span>
{ if (blogPost.updated) {
<span>{ blogPost.updated }</span>
}}
</div>
<div className="post-content" dangerouslySetInnerHTML={{__html: blogPost.body}}>
</div>
</div>
)
}
}

View File

@ -1,11 +1,11 @@
import React, {Component} from 'react'; import React from 'react';
export default class Resume extends Component{ export const Resume = () => (
render() { <div>
return (
<div className="content"> <div className="content">
<h1>Resume</h1> <h1>Resume</h1>
</div> </div>
</div>
); );
}
} export default Resume;

View File

@ -5,3 +5,4 @@ export { default as Portfolio } from './Portfolio';
export { default as Resume } from './Resume'; export { default as Resume } from './Resume';
export { default as NotFoundPage } from './NotFoundPage'; export { default as NotFoundPage } from './NotFoundPage';
export { default as App } from './App'; export { default as App } from './App';
export { default as Main } from './Main';

View File

@ -1,55 +1,41 @@
import path from 'path'; require('babel-register');
import { Server } from 'http';
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter as Router } from 'react-router-dom';
import { App } from './components/App';
const app = new Express(); var app = new (require('express'))()
const server = new Server(app); var port = process.env.PORT || 3000;
// use ejs templates require('css-modules-require-hook')({
app.set('view engine', 'ejs'); generateScopedName: '[name]__[local]___[hash:base64:5]'
app.set('views', path.join(__dirname, 'views')); })
// define the folder that will be used for static assets
app.use(Express.static(path.join(__dirname, 'static')));
// universal routing and rendering // initalize webpack dev middleware if in development context
app.get('*', (req, res) => { if (process.env.NODE_ENV === 'development') {
let markup = ''; var webpack = require('webpack')
let status = 200; var config = require('../webpack.config')
const context = {}; var devMiddleware = require('webpack-dev-middleware')
markup = renderToString( var hotDevMiddleware = require('webpack-hot-middleware')
<Router location={req.url} context={context}> var compiler = webpack(config)
<App /> var devMiddlewareConfig = {
</Router>, noInfo: true,
); stats: {colors: true},
publicPath: config.output.publicPath
// context.url will contain the URL to redirect to if a <Redirect> was used
if (context.url) {
return res.redirect(302, context.url);
} }
if (context.is404) { app.use(devMiddleware(compiler, devMiddlewareConfig))
status = 404; app.use(hotDevMiddleware(compiler))
} }
app.use(require('express').static('public'))
return res.status(status).render('index', { markup }); var serverRender = require('./serverRender')
});
// start the server app.get("*", serverRender)
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production'; app.listen(port, function(error) {
server.listen(port, (err) => { if (error) {
if (err) { console.error(error)
return console.error(err); } else {
console.info("==> Listening on port %s", port)
} }
return console.info( })
`
Server running on http://localhost:${port} [${env}]
`);
});

44
src/serverRender.js Normal file
View File

@ -0,0 +1,44 @@
import 'babel-polyfill'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter as Router } from 'react-router-dom'
import { App } from './components/App'
function serverRender(req, res) {
let markup = '';
let status = 200;
const context = {}
markup = renderToString(
<Router location={req.url} context={context}>
<App />
</Router>,
);
return res.status(status).send(renderFullPage(markup));
}
function renderFullPage(html) {
return `
<!DOCTYPE html>
<html>
<head>
<title>Redux Hello World</title>
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Inconsolata|Open+Sans|Roboto|Montserrat|Concert+One" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous">
</head>
<body>
<div id="root">${process.env.NODE_ENV === 'production' ? html : `<div>${html}</div>`}</div>
<script src="/static/vendor.js"></script>
<script src="/static/bundle.js"></script>
</body>
</html>
`
}
module.exports = serverRender

File diff suppressed because one or more lines are too long

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Portfolio</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Inconsolata|Open+Sans|Roboto|Montserrat|Concert+One" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous">
</head>
<body>
<div id="app"><%- markup -%></div>
<script src="/js/bundle.js"></script>
</body>
</html>

19
temp
View File

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Portfolio</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Inconsolata|Open+Sans|Roboto|Montserrat|Concert+One" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous">
</head>
<body>
<div id="app">
<div data-reactroot="" data-reactid="1" data-react-checksum="-1250583058"><div id="cover-page" class="cover-page-collapsed" data-reactid="2"><div id="cover-page-content" data-reactid="3"><div data-reactid="4"><h1 id="cover-page-name" data-reactid="5"><a href="/" data-reactid="6">Matúš Námešný</a></h1></div><div class="social" data-reactid="7"><a href="https://github.com/LordMathis" data-reactid="8"><i class="fa fa-github fa-3x" data-reactid="9"></i></a><a href="https://twitter.com/matus_n" data-reactid="10"><i class="fa fa-twitter fa-3x" data-reactid="11"></i></a><a href="mailto:matus@namesny.com" data-reactid="12"><i class="fa fa-envelope-o fa-3x" aria-hidden="true" data-reactid="13"></i></a></div><div class="menu-links" data-reactid="14"><ul data-reactid="15"><li data-reactid="16"><a href="/about" data-reactid="17">About</a></li><li data-reactid="18"><a href="/blog" data-reactid="19">Blog</a></li><li data-reactid="20"><a href="/portfolio" data-reactid="21">Portfolio</a></li><li data-reactid="22"><a href="/resume" data-reactid="23">Resume</a></li></ul></div></div></div><div class="content" data-reactid="24"><h1 data-reactid="25">404</h1><h2 data-reactid="26">Page not found!</h2><p data-reactid="27"><a href="/" data-reactid="28">Go back to the main page</a></p></div></div> </div>
<script src="/js/bundle.js"></script>
</body>
</html>

View File

View File

@ -1,19 +1,46 @@
const path = require('path'); const { resolve, join } = require('path')
const webpack = require('webpack')
module.exports = { const config = {
entry: [ devtool: 'cheap-eval-source-map',
'./src/app-client.js' context: resolve(__dirname, 'src'),
], entry: {
home: [
'webpack-hot-middleware/client',
'./app-client.js'
]
},
output: { output: {
path: path.join(__dirname, 'src', 'static', 'js'), path: resolve(__dirname,'public/static'),
publicPath: "/js/", filename: 'bundle.js',
filename: 'bundle.js' publicPath: '/static/'
}, },
module: { module: {
loaders: [ rules: [
{test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"}, {
{test: /\.json$/, exclude: /node_modules/, loader: 'json-loader' }, test: /\.js$/,
{test: /\.(png|jpg)$/, exclude: /node_modules/, loader: 'url-loader'}, use: [
'babel-loader'
],
exclude: '/node_modules/'
},
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
{
loader: 'postcss-loader'
}
]
},
{test: /\.scss$/, {test: /\.scss$/,
use: [{ use: [{
loader: "style-loader" // creates style nodes from JS strings loader: "style-loader" // creates style nodes from JS strings
@ -22,8 +49,19 @@ module.exports = {
}, { }, {
loader: "sass-loader" // compiles Sass to CSS loader: "sass-loader" // compiles Sass to CSS
}] }]
} },
{
test: /\.(png|jpg)$/,
exclude: /node_modules/,
loader: 'url-loader'
},
] ]
}, },
plugins: [] plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.NamedModulesPlugin()
]
} }
module.exports = config

69
webpack.prod.config.js Normal file
View File

@ -0,0 +1,69 @@
const { resolve, join } = require('path')
const webpack = require('webpack')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const config = {
context: resolve(__dirname, 'src'),
entry: {
bundle: [
'./app-client.js'
],
'vendor/js': [
'react',
'react-dom',
'redux',
'react-redux'
]
},
output: {
path: resolve(__dirname, 'public/static'),
filename: '[name].js',
publicPath: '/static/'
},
module: {
rules: [
{
test: /\.js$/,
use: [
'babel-loader'
],
exclude: '/node_modules/'
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]_[local]___[hash:base64:5]'
}
},
{
loader: 'postcss-loader'
}
]
})
}
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
// this assumes your vendor imports exist in the node_modules directory
return module.context && module.context.indexOf('node_modules') !== -1
}
}),
new ExtractTextPlugin({
filename: '[name].css',
disable: false,
allChunks: true
})
]
}
module.exports = config