diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..bd20dc17 --- /dev/null +++ b/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": [ + "es2015", + "react" + ] +} diff --git a/.eslintrc b/.eslintrc index 13e131b0..48c7adcf 100644 --- a/.eslintrc +++ b/.eslintrc @@ -28,22 +28,39 @@ // Ignore React because it's needed before ReactDOM "varsIgnorePattern": "React" } - ] + ], + + "react/jsx-no-duplicate-props": 2, + "react/jsx-no-undef": 2, + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/react-in-jsx-scope": 2 }, "env": { "es6": true, "browser": true, "node": true }, - "extends": "eslint:recommended", "ecmaFeatures": { "jsx": true, "modules": true, "experimentalObjectRestSpread": false }, + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true, + "modules": true, + "experimentalObjectRestSpread": false + }, + }, + "plugins": [ "react" ], + "extends": ["eslint:recommended"], + // Custom Globals "globals": { "app": true, diff --git a/.gitignore b/.gitignore index facebdad..3c742384 100644 --- a/.gitignore +++ b/.gitignore @@ -1,231 +1,12 @@ -## Sublime Text -*.sublime-project -*.sublime-workspace - -################# -## Eclipse -################# - -*.pydevproject -.project -.metadata -bin/ -tmp/ -*.tmp -*.bak -*.swp -*~.nib -local.properties -.classpath -.settings/ -.loadpath - -# External tool builders -.externalToolBuilders/ - -# Locally stored "Eclipse launch configurations" -*.launch - -# CDT-specific -.cproject - -# PDT-specific -.buildpath - - -################# -## Visual Studio -################# - -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.sln.docstates - -# Build results - -[Dd]ebug/ -[Rr]elease/ -x64/ -[Bb]in/ -[Oo]bj/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -*_i.c -*_p.c -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.log -*.scc - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -*.ncrunch* -.*crunch*.local.xml - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.Publish.xml -*.pubxml - -# NuGet Packages Directory -## TODO: If you have NuGet Package Restore enabled, uncomment the next line -#packages/ - -# Windows Azure Build Output -csx -*.build.csdef - -# Windows Store app package directory -AppPackages/ - -# Others -sql/ -*.Cache -ClientBin/ -[Ss]tyle[Cc]op.* -~$* -*~ -*.dbmdl -*.[Pp]ublish.xml -*.pfx -*.publishsettings - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -App_Data/*.mdf -App_Data/*.ldf - -############# -## Windows detritus -############# - -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Mac crap -.DS_Store - - -############# -## Python -############# - -*.py[co] - -# Packages -*.egg -*.egg-info -dist/ -eggs/ -parts/ -var/ -sdist/ -develop-eggs/ -.installed.cfg - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -.tox - -#Translations -*.mo - -#Mr Developer -.mr.developer.cfg - - - ############# ## Node ############# node_modules/ +npm-debug.log ############# -## Generated Public Files +## Generated Build Files ############# -public/ +build/ diff --git a/Readme.md b/Readme.md index 475949af..8b4a9ae0 100644 --- a/Readme.md +++ b/Readme.md @@ -1,18 +1,36 @@ -stk-toolkit -============= +

:star2: universal-dev-toolkit :star2:

+

Javascript Development Toolkit by @stoikerty, kindly supported by BrowserStack-Image BrowserStack.

-Install Node : [Node Platform](https://nodejs.org/)
-**Start Server** : `npm run server`
-**Start Asset Watcher** : `npm run watch`
-*( `npm run build` builds files for production but needs personalised code-changes within gulp config & tasks )* +### How to Use / Getting started quickly +- Install Node : [Node Platform](https://nodejs.org/) *(I'm using v5.6.0 but v4.2 LTS should work too)*
+- **Install the dependencies via npm** : `npm install`
+- **Start Server with Asset Watcher** : `npm run dev`
-Now you should be ready to go to start building your project. +You should now be ready to start building your project. If it doesn't work, feel free to [report an issue or help somebody out](https://github.com/stoikerty/universal-dev-toolkit/issues). ---- -If you are looking for a resource to learn from, have a look at the **Human JavaScript** video course titled ["Build an App with React and Ampersand"](http://learn.humanjavascript.com/react-ampersand) or read the ["Human JavaScript Book"](http://read.humanjavascript.com/) by [@HenrikJoreteg](twitter.com/henrikjoreteg) +:point_right: Your source-files will be **hot-reloaded** and proxied via `http://localhost:3000`. + +*You will be working with [Universal Javascript](https://medium.com/@mjackson/universal-javascript-4761051b7ae9#.llvvuk4l5), managed via [webpack](https://webpack.github.io/), therefore your source-code located in `src` will be divided into 2 directories, `client` and `server`. The `layout.html` is located in `src\server\views`*. + +I use [Express](http://expressjs.com/) with [React-Router](https://github.com/reactjs/react-router), [React](https://facebook.github.io/react/) and [SCSS](http://sass-lang.com/) with [Autoprefixer](https://github.com/postcss/autoprefixer) to build my projects. There are a few customisations although I kept the files to a minimum to allow for exploration and you being able to change things to your liking. +

--- -:point_right: A Server is fired on `localhost:2000`, while the watch-runner proxies it through [BrowserSync](http://www.browsersync.io/) on `localhost:3000` (default). BrowserSync will reload on file-changes and synchronise scrolling etc. on any browsers connected to `http://localhost:3000`. + +##### Creating a Build / How webpack is configured +- Build production files for transferring to Server with `npm run build`. The server runs on port `2000`. +- Lint your files using [eslint](http://eslint.org/) with `npm run lint`. + +Have a look at the `package.json` for a full list of dependencies. The webpack folder contains a **`webpack/config.js`** that is used both for running **`webpack/development.js`** (via `npm run dev`) and **`webpack/production.js`** (via `npm run build`). + +##### Decisions :foggy: + +I opted to use [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) and [webpack-hot-middleware](https://github.com/glenjamin/webpack-hot-middleware) for adding hot-reload functionality via a server that you can customize separately in the `src`-folder. The state of React-components is not kept as I'm looking to work with Redux, I got the idea to stop using unsafe transforms from and reduce the complexity of Babel Transforms via [an Article I read "Hot Reloading in React - *or, an Ode to Accidental Complexity*"](https://medium.com/@dan_abramov/hot-reloading-in-react-1140438583bf#.3mce9tv45) and the resulting discussion in [a Redux pull-request](https://github.com/reactjs/redux/pull/1455). + +CSS is imported via [css-modules](https://github.com/css-modules/css-modules). If you have never heard about css-modules, read ["CSS Modules - *Welcome to the Future*"](http://glenmaddern.com/articles/css-modules). + +Currently there is no test-suite. I might add one if I get more exposure into using tests myself. Although I do like keeping the toolkit simple and extensible instead of adding all sorts of dependencies for the sake of having more features. Feel free to add your own if you need it. --- -kindly supported by ![BrowserStack-Image](https://raw.githubusercontent.com/stoikerty/stk-toolkit/master/browserstack-logo.png) [BrowserStack](https://www.browserstack.com) + +*For more information, see [the release PR](https://github.com/stoikerty/universal-dev-toolkit/pull/1).* diff --git a/browserstack-logo.png b/browserstack-logo.png deleted file mode 100644 index 36741c2c..00000000 Binary files a/browserstack-logo.png and /dev/null differ diff --git a/gulp/assets-version.json b/gulp/assets-version.json deleted file mode 100644 index a326682f..00000000 --- a/gulp/assets-version.json +++ /dev/null @@ -1 +0,0 @@ -{"assetsVersion":"/assets"} \ No newline at end of file diff --git a/gulp/assets/files/Favicon.png b/gulp/assets/files/Favicon.png deleted file mode 100644 index fd76d825..00000000 Binary files a/gulp/assets/files/Favicon.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/android-chrome-144x144.png b/gulp/assets/files/favicon-files/android-chrome-144x144.png deleted file mode 100644 index 7a781e03..00000000 Binary files a/gulp/assets/files/favicon-files/android-chrome-144x144.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/android-chrome-192x192.png b/gulp/assets/files/favicon-files/android-chrome-192x192.png deleted file mode 100644 index aaa58300..00000000 Binary files a/gulp/assets/files/favicon-files/android-chrome-192x192.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/android-chrome-36x36.png b/gulp/assets/files/favicon-files/android-chrome-36x36.png deleted file mode 100644 index 42c08aab..00000000 Binary files a/gulp/assets/files/favicon-files/android-chrome-36x36.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/android-chrome-48x48.png b/gulp/assets/files/favicon-files/android-chrome-48x48.png deleted file mode 100644 index d0385b8b..00000000 Binary files a/gulp/assets/files/favicon-files/android-chrome-48x48.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/android-chrome-72x72.png b/gulp/assets/files/favicon-files/android-chrome-72x72.png deleted file mode 100644 index 191606bc..00000000 Binary files a/gulp/assets/files/favicon-files/android-chrome-72x72.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/android-chrome-96x96.png b/gulp/assets/files/favicon-files/android-chrome-96x96.png deleted file mode 100644 index e5d68b06..00000000 Binary files a/gulp/assets/files/favicon-files/android-chrome-96x96.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-114x114.png b/gulp/assets/files/favicon-files/apple-touch-icon-114x114.png deleted file mode 100644 index 2c281b4e..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-114x114.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-120x120.png b/gulp/assets/files/favicon-files/apple-touch-icon-120x120.png deleted file mode 100644 index 6092a93b..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-120x120.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-144x144.png b/gulp/assets/files/favicon-files/apple-touch-icon-144x144.png deleted file mode 100644 index 7a781e03..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-144x144.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-152x152.png b/gulp/assets/files/favicon-files/apple-touch-icon-152x152.png deleted file mode 100644 index ee3aa4eb..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-152x152.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-180x180.png b/gulp/assets/files/favicon-files/apple-touch-icon-180x180.png deleted file mode 100644 index e8a78065..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-180x180.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-57x57.png b/gulp/assets/files/favicon-files/apple-touch-icon-57x57.png deleted file mode 100644 index 4eaa37c0..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-57x57.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-60x60.png b/gulp/assets/files/favicon-files/apple-touch-icon-60x60.png deleted file mode 100644 index b4c7b046..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-60x60.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-72x72.png b/gulp/assets/files/favicon-files/apple-touch-icon-72x72.png deleted file mode 100644 index 191606bc..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-72x72.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-76x76.png b/gulp/assets/files/favicon-files/apple-touch-icon-76x76.png deleted file mode 100644 index 3feb7d09..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-76x76.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon-precomposed.png b/gulp/assets/files/favicon-files/apple-touch-icon-precomposed.png deleted file mode 100644 index e8a78065..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon-precomposed.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/apple-touch-icon.png b/gulp/assets/files/favicon-files/apple-touch-icon.png deleted file mode 100644 index e8a78065..00000000 Binary files a/gulp/assets/files/favicon-files/apple-touch-icon.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/browserconfig.xml b/gulp/assets/files/favicon-files/browserconfig.xml deleted file mode 100644 index ec562ac3..00000000 --- a/gulp/assets/files/favicon-files/browserconfig.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - #da532c - - - diff --git a/gulp/assets/files/favicon-files/favicon-16x16.png b/gulp/assets/files/favicon-files/favicon-16x16.png deleted file mode 100644 index 5dfd7d66..00000000 Binary files a/gulp/assets/files/favicon-files/favicon-16x16.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/favicon-32x32.png b/gulp/assets/files/favicon-files/favicon-32x32.png deleted file mode 100644 index 4594a8b3..00000000 Binary files a/gulp/assets/files/favicon-files/favicon-32x32.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/favicon-96x96.png b/gulp/assets/files/favicon-files/favicon-96x96.png deleted file mode 100644 index e5d68b06..00000000 Binary files a/gulp/assets/files/favicon-files/favicon-96x96.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/favicon.ico b/gulp/assets/files/favicon-files/favicon.ico deleted file mode 100644 index cf0776c0..00000000 Binary files a/gulp/assets/files/favicon-files/favicon.ico and /dev/null differ diff --git a/gulp/assets/files/favicon-files/manifest.json b/gulp/assets/files/favicon-files/manifest.json deleted file mode 100644 index fb5c1623..00000000 --- a/gulp/assets/files/favicon-files/manifest.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "My app", - "icons": [ - { - "src": "\/favicon-files\/android-chrome-36x36.png?v=2", - "sizes": "36x36", - "type": "image\/png", - "density": 0.75 - }, - { - "src": "\/favicon-files\/android-chrome-48x48.png?v=2", - "sizes": "48x48", - "type": "image\/png", - "density": 1.0 - }, - { - "src": "\/favicon-files\/android-chrome-72x72.png?v=2", - "sizes": "72x72", - "type": "image\/png", - "density": 1.5 - }, - { - "src": "\/favicon-files\/android-chrome-96x96.png?v=2", - "sizes": "96x96", - "type": "image\/png", - "density": 2.0 - }, - { - "src": "\/favicon-files\/android-chrome-144x144.png?v=2", - "sizes": "144x144", - "type": "image\/png", - "density": 3.0 - }, - { - "src": "\/favicon-files\/android-chrome-192x192.png?v=2", - "sizes": "192x192", - "type": "image\/png", - "density": 4.0 - } - ] -} diff --git a/gulp/assets/files/favicon-files/mstile-144x144.png b/gulp/assets/files/favicon-files/mstile-144x144.png deleted file mode 100644 index d5fbc5c1..00000000 Binary files a/gulp/assets/files/favicon-files/mstile-144x144.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/mstile-150x150.png b/gulp/assets/files/favicon-files/mstile-150x150.png deleted file mode 100644 index dda0ff40..00000000 Binary files a/gulp/assets/files/favicon-files/mstile-150x150.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/mstile-310x150.png b/gulp/assets/files/favicon-files/mstile-310x150.png deleted file mode 100644 index 06aa8476..00000000 Binary files a/gulp/assets/files/favicon-files/mstile-310x150.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/mstile-310x310.png b/gulp/assets/files/favicon-files/mstile-310x310.png deleted file mode 100644 index 7acf6834..00000000 Binary files a/gulp/assets/files/favicon-files/mstile-310x310.png and /dev/null differ diff --git a/gulp/assets/files/favicon-files/mstile-70x70.png b/gulp/assets/files/favicon-files/mstile-70x70.png deleted file mode 100644 index c41644de..00000000 Binary files a/gulp/assets/files/favicon-files/mstile-70x70.png and /dev/null differ diff --git a/gulp/assets/files/favicon.ico b/gulp/assets/files/favicon.ico deleted file mode 100644 index e69de29b..00000000 diff --git a/gulp/assets/files/index.html b/gulp/assets/files/index.html deleted file mode 100644 index bf254c24..00000000 --- a/gulp/assets/files/index.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - @stoikerty - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/gulp/assets/javascript/app.js b/gulp/assets/javascript/app.js deleted file mode 100644 index f08f2b94..00000000 --- a/gulp/assets/javascript/app.js +++ /dev/null @@ -1,25 +0,0 @@ -// Preconfigure the `app`-object -import './bootstrap'; -import AppBody from './AppBody'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import domready from 'domready'; - -// import individual utils -const { queryByHook } = app.utils; - -class App { - constructor() { - app.articles = []; - - domready(()=>{ - ReactDOM.render(( - - ), queryByHook(document, 'app-body')); - }); - } -} - -// start up the app with shared coffeescript objects -app.instance = new App(); diff --git a/gulp/assets/javascript/bootstrap.js b/gulp/assets/javascript/bootstrap.js deleted file mode 100644 index f03ba3e9..00000000 --- a/gulp/assets/javascript/bootstrap.js +++ /dev/null @@ -1,40 +0,0 @@ -// Create `window.app`-object -window.app = window.app || {}; - -// Set which environment we are running -app.isDev = window.isDev || false; - -// Create application logging functionality -/*eslint-disable no-console */ -app.log = function() { - if (app.isDev && window.console && window.console.log) - Function.apply.call(console.log, console, arguments); -}; -app.warn = function() { - if (app.isDev && window.console && window.console.warn) - Function.apply.call(console.warn, console, arguments); -}; -/*eslint-enable no-console */ - -// Utilities -// --- -import assetPath from './utils/assetPath'; -import breakpoint from './utils/breakpoint'; -import queryByHook from './utils/queryByHook'; -import queryAllByHook from './utils/queryAllByHook'; - -app.utils = { - // Dependencies >> window.assetPath - assetPath, - - breakpoint, - queryByHook, - queryAllByHook, -}; - -// Polyfills -// --- -// Polyfill for `fetch` (which also needs `es6-promise` polyfill) -import 'whatwg-fetch'; -import promise from 'es6-promise'; -promise.polyfill(); diff --git a/gulp/assets/javascript/utils/assetPath.js b/gulp/assets/javascript/utils/assetPath.js deleted file mode 100644 index 37a72d55..00000000 --- a/gulp/assets/javascript/utils/assetPath.js +++ /dev/null @@ -1,5 +0,0 @@ -export default (requestedFile)=> { - let assetPath = window.assetPath || '`window.assetPath` is not defined'; - - return assetPath + requestedFile; -}; diff --git a/gulp/assets/javascript/utils/breakpoint.js b/gulp/assets/javascript/utils/breakpoint.js deleted file mode 100644 index 394e69bd..00000000 --- a/gulp/assets/javascript/utils/breakpoint.js +++ /dev/null @@ -1,47 +0,0 @@ -// Check whether a given breakpoint exists -// -// Examples: -// if (breakpoint('phone smart')) -// runFunctionForSmallDevices(); -// -// if (breakpoint('tablet7 tablet10 pcsmall pclarge')) -// runFunctionForLargeDevices(); - -export default (devices)=> { - // split string into array for easier processing - devices = devices.split(" "); - - let breakpointExists = false; - // Should be the equal to variables `stylesheets/_global-config.scss` - let breakpoints = [ - { name: 'phone', width: 0 }, - { name: 'smart', width: 300 }, - { name: 'tablet7', width: 440 }, - { name: 'tablet10', width: 768 }, - { name: 'pcsmall', width: 992 }, - { name: 'pclarge', width: 1200 } - ]; - // Cross-browser @media (width) and @media (height) values - // http://stackoverflow.com/questions/1248081/get-the-browser-viewport-dimensions-with-javascript - let width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); - - // return true if one of the called breakpoints exists - for (let i=0; i< breakpoints.length; i++){ - if (devices.indexOf(breakpoints[i].name) > -1) { - let minWidth = breakpoints[i].width; - let maxWidth; - - if (i === (breakpoints.length - 1)) - maxWidth = 999999; - else - maxWidth = breakpoints[i+1].width; - - - if ((width > minWidth) && (width < maxWidth)){ - breakpointExists = true; - } - } - } - - return breakpointExists; -}; diff --git a/gulp/assets/javascript/utils/queryAllByHook.js b/gulp/assets/javascript/utils/queryAllByHook.js deleted file mode 100644 index aa6919a5..00000000 --- a/gulp/assets/javascript/utils/queryAllByHook.js +++ /dev/null @@ -1,3 +0,0 @@ -export default (el, hookName)=> { - return el.querySelectorAll('[data-jshook~="' + hookName + '"]'); -}; diff --git a/gulp/assets/javascript/utils/queryByHook.js b/gulp/assets/javascript/utils/queryByHook.js deleted file mode 100644 index 3998b0db..00000000 --- a/gulp/assets/javascript/utils/queryByHook.js +++ /dev/null @@ -1,3 +0,0 @@ -export default (el, hookName)=> { - return el.querySelector('[data-jshook~="' + hookName + '"]'); -}; diff --git a/gulp/assets/stylesheets/_default-html-stylesheet.scss b/gulp/assets/stylesheets/_default-html-stylesheet.scss deleted file mode 100644 index 0bf4ff85..00000000 --- a/gulp/assets/stylesheets/_default-html-stylesheet.scss +++ /dev/null @@ -1,115 +0,0 @@ -html, address, -blockquote, -body, dd, div, -dl, dt, fieldset, form, -frame, frameset, -h1, h2, h3, h4, -h5, h6, noframes, -ol, p, ul, center, -dir, hr, menu, pre { display: block; unicode-bidi: embed } - -li { display: list-item } - -head { display: none } - -table { display: table } - -tr { display: table-row } - -thead { display: table-header-group } - -tbody { display: table-row-group } - -tfoot { display: table-footer-group } - -col { display: table-column } - -colgroup { display: table-column-group } - -td, th { display: table-cell } - -caption { display: table-caption } - -th { font-weight: 600; text-align: center } - -caption { text-align: center } - -body { margin: 8px } - -h1 { font-size: 2em; margin: .67em 0 } -h2 { font-size: 1.5em; margin: .75em 0 } -h3 { font-size: 1.17em; margin: .83em 0 } -h4, p, -blockquote, ul, -fieldset, form, -ol, dl, dir, -menu { margin: 1.12em 0 } -h5 { font-size: .83em; margin: 1.5em 0 } -h6 { font-size: .75em; margin: 1.67em 0 } - -h1, h2, h3, h4, -h5, h6, b, -strong { font-weight: 600; } - -blockquote { margin-left: 40px; margin-right: 40px } -i, cite, em, -var, address { font-style: italic } -pre, tt, code, -kbd, samp { font-family: monospace } -pre { white-space: pre } - -button, textarea, -input, select { display: inline-block } - -big { font-size: 1.17em } -small, sub, sup { font-size: .83em } -sub { vertical-align: sub } -sup { vertical-align: super } - -table { border-spacing: 2px; } -thead, tbody, -tfoot { vertical-align: middle } -td, th, tr { vertical-align: inherit } - -s, strike, del { text-decoration: line-through } - -hr { border: 1px inset } - -ol, ul, dir, -menu, dd { margin-left: 40px } -ol { list-style-type: decimal } -ol ul, ul ol, -ul ul, ol ol { margin-top: 0; margin-bottom: 0 } - -u, ins { text-decoration: underline } - -br:before { content: "\A"; white-space: pre-line } - -// Deprecated -center { text-align: center } - -:link, :visited { text-decoration: underline } - -:focus { outline: thin dotted invert } - - -/* Begin bidirectionality settings (do not change) */ -BDO[DIR="ltr"] { direction: ltr; unicode-bidi: bidi-override } - -BDO[DIR="rtl"] { direction: rtl; unicode-bidi: bidi-override } - - -*[DIR="ltr"] { direction: ltr; unicode-bidi: embed } - -*[DIR="rtl"] { direction: rtl; unicode-bidi: embed } - - -@media print { - h1 { page-break-before: always } - - h1, h2, h3, - h4, h5, h6 { page-break-after: avoid } - - ul, ol, dl { page-break-before: avoid } - -} diff --git a/gulp/assets/stylesheets/app-body/_config.scss b/gulp/assets/stylesheets/app-body/_config.scss deleted file mode 100644 index b3e937a2..00000000 --- a/gulp/assets/stylesheets/app-body/_config.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../global-config'; diff --git a/gulp/assets/stylesheets/app-body/_style.scss b/gulp/assets/stylesheets/app-body/_style.scss deleted file mode 100644 index 9dc28a6e..00000000 --- a/gulp/assets/stylesheets/app-body/_style.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'config'; - -// application styles diff --git a/gulp/assets/stylesheets/app.scss b/gulp/assets/stylesheets/app.scss deleted file mode 100644 index ee3f44f7..00000000 --- a/gulp/assets/stylesheets/app.scss +++ /dev/null @@ -1,10 +0,0 @@ -// retrieve configuration -@import 'global-config'; - -@import 'default-html-stylesheet'; - -// style specific to the application -@import 'application/style'; - -// page-specific styling -@import 'app-body/style'; diff --git a/gulp/assets/stylesheets/application/_config.scss b/gulp/assets/stylesheets/application/_config.scss deleted file mode 100644 index b3e937a2..00000000 --- a/gulp/assets/stylesheets/application/_config.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../global-config'; diff --git a/gulp/assets/stylesheets/application/_style.scss b/gulp/assets/stylesheets/application/_style.scss deleted file mode 100644 index af264a38..00000000 --- a/gulp/assets/stylesheets/application/_style.scss +++ /dev/null @@ -1,34 +0,0 @@ -@import 'config'; - -// "hidden" class for application, used for prototyping convenience -.display-none{ - display : none !important; -} - -// style toggles for the body -body{ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - // Body Style - font-family : 'Source Sans Pro', Verdana, Arial, sans-serif; - margin : 0; - background-color : $white-96; - - &.position-fixed{ - position : fixed !important; - } - &.overflow-hidden{ - overflow : hidden !important; - } - - // Remove 300ms click-delay for IE11+ - a[href], button, .btn, .button { touch-action: manipulation; } - - .app-body{ - // architectural styles - } - - // defaults - img{ width : 100%; } -} diff --git a/gulp/config.js b/gulp/config.js deleted file mode 100644 index c5f79f66..00000000 --- a/gulp/config.js +++ /dev/null @@ -1,133 +0,0 @@ -var generateAssetsPath = require("./utils/generateAssetsPath"); - -var src = './gulp/assets'; -var assetsPath = generateAssetsPath({ name: 'assets'}); -var assetsHost = ''; -var proxyURL = 'localhost:2000'; -var rootDir = '.'; -var publicDir = 'public/'; -var dest = publicDir + assetsPath; - -module.exports = { - - // Live-Reloading - // =============== - - // BrowserSync options can be found here: - // http://www.browsersync.io/docs/options/ - browserSync: { - proxy: proxyURL, - - reloadDelay: 100, - - // Stop the browser from automatically opening - open: false, - // Scrolls & Form inputs on any device will be mirrored to all others. - ghostMode: { - clicks: false, - scroll: true, - forms: true, - }, - // show what browsers are connected - logConnections: true, - }, - - // JS Configuration - // ================== - // - Multiple input files can be specified - // - jshint is only used for .js files - - javascript: { - src: src + '/javascript/**/*.js', - serverSrc: src + '/javascript/**/*.js', - dest: dest + '/js', - - transforms: { - babelify: true, - }, - rootFiles: [ - { - src: src + '/javascript/app.js', - destName: 'app.js', - destDir: dest + '/js', - }, - ], - }, - - eslint: { - src: src + '/javascript/**/*.js', - }, - - // CSS Configuration - // ================== - // CSS is compiled via 'libsass' - // Settings Options: https://github.com/sass/node-sass#options - - sass: { - src: src + '/stylesheets/**/*.{sass,scss}', - watchSrc: src + '/stylesheets/**/*.{sass,scss}', - dest: dest + '/css', - - settings: { - indentedSyntax: false, // Enable .scss syntax! - imagePath: assetsPath, // Used by the image-url helper - outputStyle: 'compact', - sourceComments: false - }, - - production:{ - src: src + '/stylesheets/**/*.{sass,scss}', - settings: { - indentedSyntax: false, // Enable .scss syntax! - imagePath: assetsHost + assetsPath, // Used by the image-url helper - outputStyle: 'compact', - sourceComments: false - }, - } - }, - - // Supported Browsers via `Autoprefixer` - // see: https://github.com/ai/browserslist - autoprefixer: { - browsers: [ - '> 0.8%', - 'last 2 versions', - 'Explorer >= 9' - ] - }, - - // Static Assets - // ============== - - files: { - src: src + '/files/**/*', - dest: publicDir - }, - - publicRoot: { - src: src + '/public-root/**/*', - dest: publicDir - }, - - fonts: { - src: src + '/fonts/**/*', - dest: dest + '/fonts' - }, - - images: { - src: src + '/images/**/*', - dest: dest + '/images', - }, - - // Production Settings - // ==================== - - production: { - src: { - all: dest + '/*', - css: dest + '/*.css', - js: dest + '/*.js', - }, - dest: dest - } -}; diff --git a/gulp/tasks/browserSync.js b/gulp/tasks/browserSync.js deleted file mode 100644 index 45b5304c..00000000 --- a/gulp/tasks/browserSync.js +++ /dev/null @@ -1,7 +0,0 @@ -var gulp = require('gulp'); -var browserSync = require('browser-sync'); -var config = require('../config'); - -gulp.task('browserSync', function() { - browserSync(config.browserSync); -}); diff --git a/gulp/tasks/build.js b/gulp/tasks/build.js deleted file mode 100644 index c1a9eef1..00000000 --- a/gulp/tasks/build.js +++ /dev/null @@ -1,36 +0,0 @@ -var gulp = require('gulp'); -var gutil = require('gulp-util'); - -var start = new Date().getTime(); - -gulp.task('build', function(cb){ - gutil.log('-----------------------------'); - gutil.log(gutil.colors.yellow(' Starting Asset Builder')); - gutil.log('-----------------------------'); - - gutil.log(gutil.colors.yellow('- Compile Javascript -')); - gulp.start('run-build-step-1'); - return cb; -}); -gulp.task('run-build-step-1', ['javascript'], function(cb){ - gutil.log(gutil.colors.yellow('- Compile CSS -')); - gulp.start('run-build-step-2'); - return cb; -}); -gulp.task('run-build-step-2', ['css'], function(cb){ - gutil.log(gutil.colors.yellow('- Copy Files -')); - gulp.start('run-build-step-3'); - return cb; -}); -gulp.task('run-build-step-3', ['images', 'fonts', 'files', 'public-root'], function(cb){ - var end = new Date().getTime(); - var time = end - start; - - gutil.log('-----------------------------'); - gutil.log( - gutil.colors.yellow(' Assets processed in'), - gutil.colors.magenta((time / 1000).toFixed(1) + ' s') - ); - gutil.log('-----------------------------'); - return cb; -}); diff --git a/gulp/tasks/css.js b/gulp/tasks/css.js deleted file mode 100644 index ca56da91..00000000 --- a/gulp/tasks/css.js +++ /dev/null @@ -1,9 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config'); -var minifyCSS = require('gulp-minify-css'); - -gulp.task('css', ['sass-production'], function() { - return gulp.src(config.production.src.css) - .pipe(minifyCSS({keepBreaks:true})) - .pipe(gulp.dest(config.production.dest)); -}); diff --git a/gulp/tasks/default.js b/gulp/tasks/default.js deleted file mode 100644 index fd011cad..00000000 --- a/gulp/tasks/default.js +++ /dev/null @@ -1,3 +0,0 @@ -var gulp = require('gulp'); - -gulp.task('default', ['build']); diff --git a/gulp/tasks/eslint.js b/gulp/tasks/eslint.js deleted file mode 100644 index dc12b1c9..00000000 --- a/gulp/tasks/eslint.js +++ /dev/null @@ -1,16 +0,0 @@ -var gulp = require('gulp'); -var eslint = require('gulp-eslint'); -var config = require('../config'); - -gulp.task('eslint', function () { - return gulp.src(config.eslint.src) - // eslint() attaches the lint output to the eslint property - // of the file object so it can be used by other modules. - .pipe(eslint()) - // eslint.format() outputs the lint results to the console. - // Alternatively use eslint.formatEach() (see Docs). - .pipe(eslint.format()) - // To have the process exit with an error code (1) on - // lint error, return the stream and pipe to failAfterError last. - .pipe(eslint.failAfterError()); -}); diff --git a/gulp/tasks/files.js b/gulp/tasks/files.js deleted file mode 100644 index cbcd6860..00000000 --- a/gulp/tasks/files.js +++ /dev/null @@ -1,7 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config'); - -gulp.task('files', function() { - return gulp.src(config.files.src) - .pipe(gulp.dest(config.files.dest)); -}); diff --git a/gulp/tasks/fonts.js b/gulp/tasks/fonts.js deleted file mode 100644 index 7997f96c..00000000 --- a/gulp/tasks/fonts.js +++ /dev/null @@ -1,7 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config'); - -gulp.task('fonts', function() { - return gulp.src(config.fonts.src) - .pipe(gulp.dest(config.fonts.dest)); -}); diff --git a/gulp/tasks/images.js b/gulp/tasks/images.js deleted file mode 100644 index 54ed554f..00000000 --- a/gulp/tasks/images.js +++ /dev/null @@ -1,7 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config'); - -gulp.task('images', function() { - return gulp.src(config.images.src) - .pipe(gulp.dest(config.images.dest)); -}); diff --git a/gulp/tasks/javascript.js b/gulp/tasks/javascript.js deleted file mode 100644 index 980823cd..00000000 --- a/gulp/tasks/javascript.js +++ /dev/null @@ -1,136 +0,0 @@ -// Gulp + Browserify recipe -// ------------------------ -// Includes react JSX, coffeescript, uglify & sourcemaps -// Supports multiple input & output files - -var gulp = require('gulp'); -var gutil = require('gulp-util'); -var browserifyInc = require('browserify-incremental'); -var babelify = require('babelify'); -var babel = require('gulp-babel'); -var watchify = require('watchify'); -var source = require('vinyl-source-stream'); -var buffer = require('vinyl-buffer'); -var uglify = require('gulp-uglify'); -var parsePath = require('parse-filepath'); -var browserSync = require('browser-sync'); - -var config = require('../config'); - -// compile all javascript files -gulp.task('javascript', ['browserify']); -gulp.task('javascript-watch', ['browserify-watch']); - -// compile .js files after passing them through eslint -gulp.task('browserify', ['eslint'], function () { - var files = config.javascript.rootFiles; - var transforms = config.javascript.transforms || {}; - - return runBrowserify(files, transforms, { watch : false }); -}); - -// compile .js, run through eslint once, watch for changes -gulp.task('browserify-watch', function () { - var files = config.javascript.rootFiles; - var transforms = config.javascript.transforms || {}; - - return runBrowserify(files, transforms,{ - watch : true, - devMode : true, - }); -}); - -function runBrowserify(files, transforms, options){ - var firstBundle; - - files.forEach(function (file) { - var devMode = false; - if (options && options.devMode) { devMode = true; } - - var bundler = browserifyInc({ - entries: file.src, // Only need initial file, browserify finds the deps - debug: devMode, // Enable sourcemaps - - cache: {}, packageCache: {}, fullPaths: true, - cacheFile: './node_modules/browserify-cache.json' - }); - - // Convert ES6 syntax & JSX - if (transforms.babelify) - bundler.transform( - babelify.configure({ - presets: ['es2015', 'react'], - plugins: ['jsx-control-statements/babel'], - }) - ); - - // save the bundle creation process as a function - var createBundle = function (bundler){ - if (devMode) - return bundler.bundle() - .on('error', function(errorObject) { - console.log(errorObject.toString()); - // Keep gulp watcher from hanging on this task - if (options.watch) this.emit('end'); - else process.exit(1); - }) - .pipe(source(file.destName)) - .pipe(buffer()) - .pipe(gulp.dest(file.destDir)) - .pipe(browserSync.reload({stream:true})); - else - // Optional future improvement to reduce minified size. - // Removes log and warn messages from output: - // uglify({ - // compress: { - // pure_funcs: [ 'app.warn', 'console.warn', 'app.log', 'console.log' ] - // } - // }) - return bundler.bundle() - .on('error', function(errorObject) { - console.log(errorObject.toString()); - // Keep gulp watcher from hanging on this task - if (options.watch) this.emit('end'); - else process.exit(1); - }) - .pipe(source(file.destName)) - .pipe(buffer()) - .pipe(uglify({ compress: false })) - .pipe(gulp.dest(file.destDir)); - }; - - if (options && options.watch) { - // wrap the browserify object inside watchify object - bundler = watchify(bundler); - - // watch for changes - bundler.on('update', function(ids){ - // create a new bundle each time a file changes - - ids.forEach(function(id){ - // log each file - gutil.log( - 'File changed:', - gutil.colors.cyan(parsePath(id).basename) - ); - }); - - createBundle(bundler); - }); - - bundler.on('time', function(time){ - // log out build time - gutil.log( - 'Bundle created in', - gutil.colors.magenta((time / 1000).toFixed(1) + ' s') - ); - }); - } - - // create the bundle when the function first gets run - firstBundle = createBundle(bundler); - }); - - // return the bundle up the chain to get task first-build time - return firstBundle; -} diff --git a/gulp/tasks/public-root.js b/gulp/tasks/public-root.js deleted file mode 100644 index 79e04b1a..00000000 --- a/gulp/tasks/public-root.js +++ /dev/null @@ -1,7 +0,0 @@ -var gulp = require('gulp'); -var config = require('../config'); - -gulp.task('public-root', function() { - return gulp.src(config.publicRoot.src) - .pipe(gulp.dest(config.publicRoot.dest)); -}); diff --git a/gulp/tasks/sass.js b/gulp/tasks/sass.js deleted file mode 100644 index 93226bc9..00000000 --- a/gulp/tasks/sass.js +++ /dev/null @@ -1,35 +0,0 @@ -var gulp = require('gulp'); -var sass = require('gulp-sass'); -var sourcemaps = require('gulp-sourcemaps'); -var autoprefixer = require('gulp-autoprefixer'); -var browserSync = require('browser-sync'); -var cssBase64 = require('gulp-css-base64'); -var gulpReplace = require('gulp-replace'); - -var handleErrors = require('../utils/handleErrors'); -var config = require('../config'); - -gulp.task('sass', function () { - return gulp.src(config.sass.src) - // .pipe(sourcemaps.init()) - .pipe(sass(config.sass.settings)) - .on('error', handleErrors) - // .pipe(sourcemaps.write()) - - // .pipe(gulpReplace(config.sass.imagePathReplaceString, config.sass.production.settings.imagePath)) - // .pipe(cssBase64({ baseDir: config.sass.imageSrc })) - .pipe(autoprefixer(config.autoprefixer.browsers)) - .pipe(gulp.dest(config.sass.dest)) - .pipe(browserSync.reload({stream:true})); -}); - -gulp.task('sass-production', function () { - return gulp.src(config.sass.production.src) - .pipe(sass(config.sass.production.settings)) - .on('error', handleErrors) - - // .pipe(gulpReplace(config.sass.imagePathReplaceString, config.sass.production.settings.imagePath)) - // .pipe(cssBase64({ baseDir: config.sass.imageSrc })) - .pipe(autoprefixer(config.autoprefixer.browsers)) - .pipe(gulp.dest(config.sass.dest)); -}); diff --git a/gulp/tasks/watch.js b/gulp/tasks/watch.js deleted file mode 100644 index 48d62f09..00000000 --- a/gulp/tasks/watch.js +++ /dev/null @@ -1,35 +0,0 @@ -/* Notes: - - gulp/tasks/browserify.js handles js recompiling with watchify - - gulp/tasks/browserSync.js watches and reloads compiled files -*/ - -var gulp = require('gulp'); -var gutil = require('gulp-util'); -var watch = require('gulp-watch'); -var gaze = require('gaze'); -var config = require('../config'); - -gulp.task('watch', function(cb){ - gutil.log('-----------------------------'); - gutil.log(gutil.colors.green(' Starting Asset Watcher')); - gutil.log('-----------------------------'); - - gulp.start('run-watch'); - return cb; -}); - -var watchFiles = function(files, task){ - gaze(files, function() { - this.on('changed', function(filepath) { - gulp.start([task]); - }); - }); -} - -gulp.task('run-watch', ['javascript-watch', 'browserSync', 'sass', 'images', 'fonts', 'files', 'public-root'], function(callback) { - watchFiles(config.sass.src, 'sass'); - watchFiles(config.images.src, 'images'); - watchFiles(config.fonts.src, 'fonts'); - watchFiles(config.files.src, 'files'); - watchFiles(config.publicRoot.src, 'public-root'); -}); diff --git a/gulp/utils/generateAssetsPath.js b/gulp/utils/generateAssetsPath.js deleted file mode 100644 index 3f7923c3..00000000 --- a/gulp/utils/generateAssetsPath.js +++ /dev/null @@ -1,22 +0,0 @@ -var fs = require("fs"); -var path = require("path"); -var hashdirectory = require('hashdirectory'); -var filename = '../assets-version.json'; - -// TODO: -// production variable set here, should be integrated using custom mechanism -var production = false; - -module.exports = function(options) { - var content = { assetsVersion: '/' + (options.name || 'dev-files') }; - - if (production) { - // generate hash of the complete assets directory - var hash = hashdirectory.sync(path.resolve(__dirname, '../assets')); - content.assetsVersion = '/version-' + hash; - } - - fs.writeFileSync(path.resolve(__dirname, filename), JSON.stringify(content)); - - return content.assetsVersion; -}; diff --git a/gulp/utils/handleErrors.js b/gulp/utils/handleErrors.js deleted file mode 100644 index 9d1a4707..00000000 --- a/gulp/utils/handleErrors.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = function(errorObject) { - console.log(errorObject.toString()); - // Keep gulp from hanging on this task - this.emit('end'); -}; diff --git a/gulp/utils/readAssetsPath.js b/gulp/utils/readAssetsPath.js deleted file mode 100644 index 51e98472..00000000 --- a/gulp/utils/readAssetsPath.js +++ /dev/null @@ -1,8 +0,0 @@ -var fs = require("fs"); -var path = require("path"); -var filename = '../assets-version.json'; - -module.exports = function() { - var file = fs.readFileSync(path.resolve(__dirname, filename), "utf8"); - return JSON.parse(file).assetsVersion; -}; diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 99a2c8f6..00000000 --- a/gulpfile.js +++ /dev/null @@ -1,21 +0,0 @@ -/* - gulpfile.js - =========== - Rather than manage one giant configuration file responsible - for creating multiple tasks, each task has been broken out into - its own file in gulp/tasks. Any files in that directory get - automatically required below. - - To add a new task, simply add a new task file that directory. - gulp/tasks/default.js specifies the default set of tasks to run - when you run `gulp`. - - ---- - => loosely based on "gulp-starter" - https://github.com/greypants/gulp-starter -*/ - -var requireDir = require('require-dir'); - -// Require all tasks in gulp/tasks, including subfolders -requireDir('./gulp/tasks', { recurse: true }); diff --git a/package.json b/package.json index afb43d7d..14b36541 100644 --- a/package.json +++ b/package.json @@ -1,61 +1,68 @@ { - "name": "stk-toolkit-project", - "version": "3.0.1", + "name": "universal-dev-toolkit", + "version": "4.0.0", "description": "{ Project }", - "main": "server.js", + "main": "index.js", + "scripts": { + "build": "node_modules/.bin/nodemon --exec babel-node --debug webpack/production.js --watch webpack/production.js", + "dev": "node_modules/.bin/babel-node webpack/development.js", + "lint": "eslint src" + }, "repository": { "type": "git", - "url": "https://github.com/stoikerty/stk-toolkit.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "server": "node node_modules/nodemon/bin/nodemon server.js", - "build": "node node_modules/gulp/bin/gulp build", - "watch": "node node_modules/gulp/bin/gulp watch" + "url": "git+https://github.com/stoikerty/universal-dev-toolkit.git" }, + "keywords": [ + "stoikerty", + "webpack", + "sass", + "react", + "browserify", + "gulp", + "moonboots", + "middleman", + "stk-toolkit", + "universal-dev-toolkit" + ], "author": "Jorge Antunes", + "license": "ISC", + "bugs": { + "url": "https://github.com/stoikerty/universal-dev-toolkit/issues" + }, + "homepage": "https://github.com/stoikerty/universal-dev-toolkit#readme", "devDependencies": { - "babel-preset-es2015": "^6.3.13", - "babel-preset-react": "^6.3.13", - "babelify": "^7.2.0", - "browser-sync": "^2.2.3", - "browserify": "^9.0.3", - "browserify-incremental": "^3.0.1", - "eslint": "^1.7.3", - "eslint-plugin-react": "^3.6.3", - "gulp": "^3.8.11", - "gulp-autoprefixer": "^2.1.0", - "gulp-babel": "^6.1.1", - "gulp-css-base64": "^1.3.2", - "gulp-eslint": "^1.0.0", - "gulp-minify-css": "^0.5.1", - "gulp-replace": "^0.5.4", - "gulp-sass": "^2.1.0-beta", - "gulp-sourcemaps": "^1.5.0", - "gulp-uglify": "^1.1.0", - "gulp-util": "^3.0.4", - "gulp-watch": "^4.2.0", - "hashdirectory": "^0.1.0", - "jsx-control-statements": "^2.0.1", - "nodemon": "^1.8.1", - "parse-filepath": "^0.5.0", - "require-dir": "^0.1.0", - "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.1.0", - "watchify": "^2.4.0" + "autoprefixer": "^6.3.3", + "babel-cli": "^6.6.5", + "babel-core": "^6.7.2", + "babel-eslint": "^5.0.0", + "babel-loader": "^6.2.4", + "babel-preset-es2015": "^6.6.0", + "babel-preset-react": "^6.5.0", + "browser-sync": "^2.11.1", + "browser-sync-webpack-plugin": "^1.0.1", + "css-loader": "^0.23.1", + "css-modules-require-hook": "^4.0.0", + "eslint": "^2.4.0", + "eslint-loader": "^1.3.0", + "eslint-plugin-react": "^4.2.3", + "node-sass": "^3.4.2", + "nodemon": "^1.9.1", + "null-loader": "^0.1.1", + "postcss-loader": "^0.8.2", + "redbox-react": "^1.2.2", + "sass-loader": "^3.2.0", + "style-loader": "^0.13.0", + "webpack": "^1.12.14", + "webpack-dev-middleware": "^1.5.1", + "webpack-hot-middleware": "^2.10.0" }, "dependencies": { - "amp-each": "^1.0.1", - "body-parser": "^1.14.1", - "cson-parser": "^1.3.0", "domready": "^1.0.8", - "errorhandler": "^1.4.2", - "es6-promise": "^3.0.2", "express": "^4.13.4", - "method-override": "^2.3.5", - "react": "^0.14.0", - "react-addons-css-transition-group": "^0.14.0", - "react-dom": "^0.14.0", - "whatwg-fetch": "^0.10.1" + "express-handlebars": "^3.0.0", + "react": "^0.14.7", + "react-dom": "^0.14.7", + "react-router": "^2.0.0-rc4", + "serve-static": "^1.10.2" } } diff --git a/server.js b/server.js deleted file mode 100644 index 836acab1..00000000 --- a/server.js +++ /dev/null @@ -1,27 +0,0 @@ -var express = require("express"), - app = express(), - bodyParser = require('body-parser'), - errorHandler = require('errorhandler'), - methodOverride = require('method-override'), - hostname = process.env.HOSTNAME || 'localhost', - port = parseInt(process.env.PORT, 10) || 2000, - publicDir = process.argv[2] || __dirname + '/public'; - -app.get('/', function (req, res) { - res.sendFile(__dirname + "/public/index.html"); -}); - - -app.use(methodOverride()); -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ - extended: true -})); -app.use(express.static(publicDir)); -app.use(errorHandler({ - dumpExceptions: true, - showStack: true -})); - -console.log("Project Server listening on http://%s:%s", hostname, port); -app.listen(port); diff --git a/src/client/AppBody.js b/src/client/AppBody.js new file mode 100644 index 00000000..060193b2 --- /dev/null +++ b/src/client/AppBody.js @@ -0,0 +1,37 @@ +import React from 'react'; +import { Link } from 'react-router'; + +import s from './style/app.scss'; +import Component from './AppBody/Component'; + +export default class AppBody extends React.Component{ + constructor(props){ + super(props); + this.displayName = 'AppBody'; + + this.state = {}; + } + + render() { + return ( +
+ { '{ universal-dev-toolkit }' } + +
+ + { 'Example Page' } + + + {' Non-existing Page' } + +
+ + + +
+ { this.props.children } +
+
+ ); + } +} diff --git a/src/client/AppBody/component.js b/src/client/AppBody/component.js new file mode 100644 index 00000000..a9431552 --- /dev/null +++ b/src/client/AppBody/component.js @@ -0,0 +1,19 @@ +import React from 'react'; +import s from './component.scss'; + +export default class Component extends React.Component{ + constructor(props){ + super(props); + this.displayName = 'Component'; + + this.state = {}; + } + + render() { + return ( +
+ Styled Example Component +
+ ); + } +} diff --git a/src/client/AppBody/component.scss b/src/client/AppBody/component.scss new file mode 100644 index 00000000..0e54724e --- /dev/null +++ b/src/client/AppBody/component.scss @@ -0,0 +1,13 @@ +@import 'style/config.scss'; + +.ExampleComponent{ + // position-mixin: position, display (optional), width (optional), height (optional) + @include position(relative, block, 100%); + float : left; + clear : both; + padding : $grid * 2; + min-height: $grid * 3; + + // mixin for prototyping: color (number from 1-2), opacity (optional) + @include proto(2, 0.5); +} diff --git a/src/client/RouterContainer.js b/src/client/RouterContainer.js new file mode 100644 index 00000000..4bde1b03 --- /dev/null +++ b/src/client/RouterContainer.js @@ -0,0 +1,23 @@ +import React from 'react'; +import { Router, browserHistory, RouterContext } from 'react-router'; + +import routes from './routes'; + +export default class RouterContainer extends React.Component{ + constructor(props){ + super(props); + this.displayName = 'RouterContainer'; + + this.state = {}; + } + + render() { + return ( + } + /> + ); + } +} diff --git a/src/client/app.js b/src/client/app.js new file mode 100644 index 00000000..31e32bbd --- /dev/null +++ b/src/client/app.js @@ -0,0 +1,58 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import domready from 'domready'; +import RedBox from 'redbox-react'; +// `RouterContainer`-module is required below + +// Create Client-App with hot-reloading capabilities +class App { + constructor() { + this.render = this.render.bind(this); + this.hotReRender = this.hotReRender.bind(this); + this.renderError = this.renderError.bind(this); + this.rootElement = null; + + // When browser has finished leading, retrieve app-body element and render + domready(()=> { + this.rootElement = document.querySelector('[data-jshook~="app-body"]'); + this.render(); + + // Support hot reloading of components by rerendering via webpack & setTimeout + if (module.hot) { + module.hot.accept('./RouterContainer', () => { + setTimeout(this.hotReRender); + }); + } + }); + } + + // Render App with fresh version of required Routing module + render(){ + const RootComponent = require('./RouterContainer').default; + + ReactDOM.render( + , + this.rootElement + ); + } + + // Re-render after hot-reloading a module, display error if necessary + hotReRender(){ + try { + this.render(); + } catch (error) { + this.renderError(error); + } + } + + // Risplay an overlay for runtime errors + renderError(error){ + ReactDOM.render( + , + this.rootElement + ); + } +} + +// start up the app immediately +new App(); diff --git a/src/client/routes.js b/src/client/routes.js new file mode 100644 index 00000000..4d3f9652 --- /dev/null +++ b/src/client/routes.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { Route } from 'react-router'; + +import AppBody from './AppBody'; +import ExamplePage from './views/ExamplePage'; +import NoMatch404 from './views/NoMatch404'; + +export default ( + + {/* Make needed component available */} + + + {/* Screen for non-existing routes */} + + +); diff --git a/gulp/assets/stylesheets/_global-config.scss b/src/client/style/_config.scss similarity index 78% rename from gulp/assets/stylesheets/_global-config.scss rename to src/client/style/_config.scss index 41e9b4e7..36f89003 100644 --- a/gulp/assets/stylesheets/_global-config.scss +++ b/src/client/style/_config.scss @@ -2,9 +2,6 @@ // Caution! these have an effect on a lot of elements // -- -// compass config option: make gradients work on IE -$experimental-support-for-svg: true; - // Define repsonsive breakpoints for application $breakpoint-phone : 0px; $breakpoint-smart : 300px; @@ -27,13 +24,6 @@ $use-em-breakpoints : false; // useful helper mixins @import "mixins/_helpers.scss"; -// Our custom function for rewriting the urls of background-images for caching -// see: "imagePathReplaceString" in `/gulp/config.js` -$image-path-replace-string: "__IMAGE_URL__" !default; -@function image-url($url) { - @return url("#{$image-path-replace-string}#{$url}"); -} - // font-settings for app (get passed through mixin as defaults) $text-color-default : #333; $font-xxlarge : 30px; @@ -45,10 +35,10 @@ $font-xsmall : 12px; $font-path : '../fonts'; @import "mixins/_font-settings.scss"; -// set common variables for use throughout the app +// a common variable for use throughout the app as simple grid-system $grid : 10px; -// New brand colors +// New brand colors (Use your own!) $brand-green : #14a58e; $brand-red : #e01d58; $brand-blue : #3597ad; diff --git a/src/client/style/app.scss b/src/client/style/app.scss new file mode 100644 index 00000000..dcd47eb1 --- /dev/null +++ b/src/client/style/app.scss @@ -0,0 +1,26 @@ +// retrieve configuration +@import './config.scss'; + +// Global-style specific to the application +body:global{ + // Body Style. Puh-lease no margin and better contrast + font-family : 'Source Sans Pro', Verdana, Arial, sans-serif; + color : #282828; + margin : 0; + background-color : $white-96; + + // make fonts look nicer + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.AppBody{ + // Style Defaults. Use border-box & make sure images don't overflow. + *{ box-sizing : border-box; } + img{ max-width : 100%; } + + // Remove 300ms click-delay for IE11+ + a[href], button, .btn, .button { touch-action: manipulation; } + + @include font(medium); +} diff --git a/gulp/assets/stylesheets/mixins/_font-settings.scss b/src/client/style/mixins/_font-settings.scss similarity index 100% rename from gulp/assets/stylesheets/mixins/_font-settings.scss rename to src/client/style/mixins/_font-settings.scss diff --git a/gulp/assets/stylesheets/mixins/_helpers.scss b/src/client/style/mixins/_helpers.scss similarity index 99% rename from gulp/assets/stylesheets/mixins/_helpers.scss rename to src/client/style/mixins/_helpers.scss index 6df02a7c..9f1f8348 100644 --- a/gulp/assets/stylesheets/mixins/_helpers.scss +++ b/src/client/style/mixins/_helpers.scss @@ -558,4 +558,4 @@ $pclarge : toEm($breakpoint-pclarge); // // ----------------------------------------------------------------- -// > @stoikerty https://github.com/stoikerty/stk-toolbox-helpers +// > @stoikerty https://github.com/stoikerty/universal-dev-toolkit diff --git a/gulp/assets/javascript/AppBody.js b/src/client/views/ExamplePage.js similarity index 51% rename from gulp/assets/javascript/AppBody.js rename to src/client/views/ExamplePage.js index 0c34650c..aae5a022 100644 --- a/gulp/assets/javascript/AppBody.js +++ b/src/client/views/ExamplePage.js @@ -1,17 +1,17 @@ import React from 'react'; -export default class extends React.Component{ +export default class ExamplePage extends React.Component{ constructor(props){ super(props); - this.displayName = 'AppBody'; + this.displayName = 'ExamplePage'; this.state = {}; } render() { return ( -
- { 'Hello World!' } +
+ { 'Example Page' }
); } diff --git a/src/client/views/NoMatch404.js b/src/client/views/NoMatch404.js new file mode 100644 index 00000000..0006ca13 --- /dev/null +++ b/src/client/views/NoMatch404.js @@ -0,0 +1,16 @@ +import React from 'react'; + +export default class NoMatch404 extends React.Component{ + constructor(props){ + super(props); + this.displayName = 'NoMatch404'; + + this.state = {}; + } + + render() { + return ( +
{ 'NoMatch404' }
+ ); + } +} diff --git a/src/server/app.js b/src/server/app.js new file mode 100644 index 00000000..695b16b2 --- /dev/null +++ b/src/server/app.js @@ -0,0 +1,26 @@ +import serveStatic from 'serve-static'; +import router from './router'; + +// Preconfigure the `app`-object +import './bootstrap'; + +// launch server later with webpack using start-method +app.server.start = (options={ message:null })=>{ + // serve build folder + app.server.instance.use(serveStatic('build')); + + // Listen on specified port + app.server.instance.listen(app.server.port, function(error) { + if (error) { + app.error(error); + } else { + app.log('==> 🌎 Listening on http://' + app.server.hostname + ':%s/', app.server.port); + if (options.message){ + app.log(options.message); + } + } + }); + + // start react-router + app.server.instance.use(router); +}; diff --git a/src/server/bootstrap.js b/src/server/bootstrap.js new file mode 100644 index 00000000..46263028 --- /dev/null +++ b/src/server/bootstrap.js @@ -0,0 +1,27 @@ +import express from 'express'; +import hbs from 'express-handlebars'; + +// Create Node Global +GLOBAL.app = {}; + +app.server = {}; +app.server.hostname = 'localhost'; +app.server.port = 2000; + +// Create express server instance +// -> Set the folder for html views & disable powered-by header +app.server.instance = express(); +app.server.instance.engine('html', hbs({ extname: 'html' })); +app.server.instance.set('views', process.cwd() + '/src/server/views'); +app.server.instance.set('view engine', 'html'); +app.server.instance.locals.settings['x-powered-by'] = false; +app.server.instance.disable('x-powered-by'); + +/*eslint-disable no-console */ +// Create application logging functionality. +// A neat console wrapper that keeps the correct line number. +// http://stackoverflow.com/questions/13815640/a-proper-wrapper-for-console-log-with-correct-line-number +app.log = function() { + return console.log.bind(console); +}(); +/*eslint-enable no-console */ diff --git a/src/server/router.js b/src/server/router.js new file mode 100644 index 00000000..a93b9fe7 --- /dev/null +++ b/src/server/router.js @@ -0,0 +1,26 @@ +import React from 'react'; +import ReactDOM from 'react-dom/server'; +import { match, RouterContext } from 'react-router'; + +// import client-side routes +import routes from '../client/routes'; + +// React Router Boilerplate +// Note: +// Adapted from server-rendering example: https://github.com/rackt/react-router/blob/latest/docs/guides/advanced/ServerRendering.md +export default (req, res, next)=> { + match({ routes, location: req.url }, (error, redirectLocation, renderProps) => { + if (error) { + res.status(500).send(error.message); + } else if (redirectLocation) { + res.redirect(302, redirectLocation.pathname + redirectLocation.search); + } else if (renderProps) { + // Render `layout`-template using Handlebars + res.status(200).render('layout', { + reactHtml: ReactDOM.renderToString() + }); + } else { + res.status(404).send('Not found'); + } + }); +}; diff --git a/src/server/views/layout.html b/src/server/views/layout.html new file mode 100644 index 00000000..0b941a57 --- /dev/null +++ b/src/server/views/layout.html @@ -0,0 +1,54 @@ + + + + + + + + + Universal App + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{{reactHtml}}}
+ + + + + diff --git a/webpack/config.js b/webpack/config.js new file mode 100644 index 00000000..ed9d26b0 --- /dev/null +++ b/webpack/config.js @@ -0,0 +1,158 @@ +import path from 'path'; +import webpack from 'webpack'; +import autoprefixer from 'autoprefixer'; +import BrowserSyncPlugin from 'browser-sync-webpack-plugin'; + +// ----- + +// Create shared config variables +// --- +const DEBUG = !process.argv.includes('--release'); +const VERBOSE = process.argv.includes('--verbose'); + +const clientRoot = path.resolve(__dirname, '../src/client'); +const PATHS = { + clientRoot: clientRoot, + client: path.resolve(clientRoot, 'app.js'), + build: path.resolve(__dirname, '../build') +}; + +const cssChunkNaming = '[name]__[local]___[hash:base64:5]'; +const scssConfigIncludePaths = [ PATHS.clientRoot ]; + +// ----- + +// Server-side rendering of scss files +// --- +import hook from 'css-modules-require-hook'; +import sass from 'node-sass'; + +// Implement a hook in node for `.scss`-imports that uses +// the same settings as the webpack config. +hook({ + extensions: [ '.scss' ], + + // Share naming-convention of `css-loader` + generateScopedName: cssChunkNaming, + + // Process files with same settings as `sass-loader` and return css. + preprocessCss: (cssFileData, cssFilePath) => { + // Include any paths that are part of the config, + // as well as the current path where css-file resides. + let includePaths = [].concat(scssConfigIncludePaths); + includePaths.push(path.dirname(cssFilePath)); + + return sass.renderSync({ + data: cssFileData, + includePaths: includePaths + }).css; + }, +}); + +// ----- + +// Resulting webpack config +// --- +export default { + devtool: 'source-map', + + entry: [ + 'webpack-hot-middleware/client', + PATHS.client + ], + + output: { + path: PATHS.build, + filename: 'app.js', + publicPath: '/' + }, + + plugins: [ + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.HotModuleReplacementPlugin(), + + new BrowserSyncPlugin( + // BrowserSync options - see: http://www.browsersync.io/docs/options/ + { + // Use http://localhost:3000/ for development, proxy Dev Server. + host: 'localhost', port: 3000, + proxy: 'http://localhost:2000/', + // Stop the browser from automatically opening. + open: false, + // Scrolls & Form inputs on any device will be mirrored to all others. + ghostMode: { + clicks: false, + scroll: true, + forms: true, + }, + // Show what browsers are connected. + logConnections: true, + }, + // Plugin options + { + // Prevent BrowserSync from reloading the page + // and let Webpack Dev Server take care of this. + reload: false + } + ) + ], + + module: { + loaders: [ + { + test: /\.js?$/, + loaders: [ + 'babel-loader', + 'eslint-loader' + ], + exclude: path.resolve(__dirname, '../node_modules') + }, + { + test: /\.scss$/, + loaders: [ + 'style-loader', + 'css-loader?modules&importLoaders=1&localIdentName=' + cssChunkNaming, + 'postcss-loader', + 'sass-loader' + ] + } + ] + }, + + // `sass-loader`-specific config + sassLoader: { + includePaths: scssConfigIncludePaths + }, + + // `postcss-loader`-specific config + postcss: [ + // Supported Browsers via `Autoprefixer` + // see: https://github.com/ai/browserslist + autoprefixer({ + browsers: [ + '> 0.8%', + 'last 2 versions', + 'Explorer >= 9' + ] + }) + ], + + resolve: { + modulesDirectories: [ + PATHS.clientRoot, + 'node_modules' + ] + }, + + stats: { + colors: true, + reasons: DEBUG, + hash: VERBOSE, + version: VERBOSE, + timings: true, + chunks: VERBOSE, + chunkModules: VERBOSE, + cached: VERBOSE, + cachedAssets: VERBOSE, + } +}; diff --git a/webpack/development.js b/webpack/development.js new file mode 100644 index 00000000..0d6e91f7 --- /dev/null +++ b/webpack/development.js @@ -0,0 +1,15 @@ +import webpack from 'webpack'; +import webpackDevMiddleware from 'webpack-dev-middleware'; +import webpackHotMiddleware from 'webpack-hot-middleware'; + +import config from './config'; + +// Use the express production server +import '../src/server/app'; + +const compiler = webpack(config); + +app.server.instance.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath })); +app.server.instance.use(webpackHotMiddleware(compiler)); + +app.server.start({message: '==> Browsersync should be launched soon. Use one of the Access URLs for development.'}); diff --git a/webpack/production.js b/webpack/production.js new file mode 100644 index 00000000..7c9d339e --- /dev/null +++ b/webpack/production.js @@ -0,0 +1,14 @@ +import webpack from 'webpack'; +import config from './config'; + +// Use the express production server +import '../src/server/app'; + +// compile all files necessary for serving +const compiler = webpack(config); +compiler.run((err, stats)=>{ + // output what's happening within webpack + app.log(stats.toString(config.stats)); +}); + +app.server.start();