diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a4b0b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# START Do not modify the lines between here and #END, they will be regenerated by GitIgnoreEditor +/betternavigator +/cms +/debugbar +/framework +/ideannotator +/redirectedurls +/reports +/silverstripe-scaled-uploads +/silverstripe-version-truncator +/siteconfig +# END of GitIgnoreEditor + +/node_modules +/composer.lock +/yarn.lock +/vendor +/site/dist \ No newline at end of file diff --git a/browserconfig.xml b/browserconfig.xml new file mode 100644 index 0000000..36439de --- /dev/null +++ b/browserconfig.xml @@ -0,0 +1,12 @@ + + + + + + + + + #000 + + + diff --git a/cache.appcache b/cache.appcache new file mode 100755 index 0000000..a620a24 --- /dev/null +++ b/cache.appcache @@ -0,0 +1,10 @@ +CACHE MANIFEST + +FALLBACK: +/ +/site/dist/css/app.css +/site/dist/img/logo.png +/site/dist/img/fonts/fontawesome-webfont.woff2?v=4.7.0 +/site/dist/img/fonts/fontawesome-webfont.woff?v=4.7.0 +/site/dist/img/fonts/fontawesome-webfont.ttf?v=4.7.0 +/site/dist/js/app.js \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..41733de --- /dev/null +++ b/composer.json @@ -0,0 +1,32 @@ +{ + "name": "silverstripe/installer", + "description": "The SilverStripe webpack boilerplate", + "require": { + "php": ">=5.5.0", + "silverstripe/cms": "*", + "silverstripe/framework": "3.7.x-dev", + "silverstripe/redirectedurls": "*", + "axllent/silverstripe-scaled-uploads": "*", + "jonom/silverstripe-betternavigator": "*", + "axllent/silverstripe-version-truncator": "*" + }, + "require-dev": { + "phpunit/PHPUnit": "~3.7", + "gdmedia/ss-auto-git-ignore": "^1.0", + "axyr/silverstripe-ideannotator": "dev-master", + "lekoala/silverstripe-debugbar": "^1.0" + }, + "scripts": { + "post-update-cmd": "GDM\\SSAutoGitIgnore\\UpdateScript::Go" + }, + "config": { + "process-timeout": 600, + "discard-changes": true + }, + "extra": { + "branch-alias": { + "3.x-dev": "3.6.x-dev" + } + }, + "minimum-stability": "dev" +} \ No newline at end of file diff --git a/humans.txt b/humans.txt new file mode 100755 index 0000000..7c664d2 --- /dev/null +++ b/humans.txt @@ -0,0 +1,11 @@ +/* AUTHOR */ +Name: + +/* TEAM */ +Site: https://bla-bla.com/ + +/* SITE */ +Doctype: HTML5 +IDE: PHPStorm, Sublime Text, Photoshop, Transmit +Framework: SilverStripe +Language: English \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..a216f7a --- /dev/null +++ b/manifest.json @@ -0,0 +1,49 @@ +{ + "name": "SilverStripe", + "short_name": "SilverStripe website", + "description": "", + "dir": "auto", + "lang": "en-US", + "display": "standalone", + "orientation": "any", + "start_url": "/?homescreen=1", + "theme_color": "#000000", + "background_color": "#000000", + "icons": [{ + "src": "/dist/icons/android-chrome-36x36.png", + "sizes": "36x36", + "type": "image/png" + }, { + "src": "/dist/icons/android-chrome-48x48.png", + "sizes": "48x48", + "type": "image/png" + }, { + "src": "/dist/icons/android-chrome-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, { + "src": "/dist/icons/android-chrome-96x96.png", + "sizes": "96x96", + "type": "image/png" + }, { + "src": "/dist/icons/android-chrome-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, { + "src": "/dist/icons/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, { + "src": "/dist/icons/android-chrome-256x256.png", + "sizes": "256x256", + "type": "image/png" + }, { + "src": "/dist/icons/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + }, { + "src": "/dist/icons/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + }] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100755 index 0000000..aa58383 --- /dev/null +++ b/package.json @@ -0,0 +1,110 @@ +{ + "name": "ss-webpack-boilerplate", + "version": "1.0.0", + "description": "Lets you create SilverStripe faster", + "author": "Tony Air ", + "license": "MIT", + "private": false, + "engines": { + "yarn": ">= 1.0.0" + }, + "scripts": { + "start": "cross-env NODE_ENV=development webpack-dev-server -d --config webpack.config.dev.js", + "dash": "cross-env NODE_ENV=development webpack-dashboard -- webpack-dev-server --config webpack.config.dev.js", + "prebuild": "rimraf build", + "build": "cross-env NODE_ENV=production webpack -p --config webpack.config.prod.js --progress" + }, + "dependencies": { + "bootstrap": "twbs/bootstrap#>= 3.1.0", + "favicons-webpack-plugin": "^0.0.7", + "jquery": "^3.3.1", + "js-yaml": "^3.10.0", + "popper": "^1.0.1", + "popper.js": "^1.12.9" + }, + "devDependencies": { + "exports-loader": "^0.7.0", + "favicons-webpack-plugin": "^0.0.7", + "@silverstripe/eslint-config": "0.0.2", + "autoprefixer": "^7.2.5", + "babel-core": "^6.26.0", + "babel-loader": "^7.1.2", + "babel-plugin-transform-react-jsx": "^6.24.1", + "babel-preset-es2015": "^6.24.1", + "babel-preset-react": "^6.24.1", + "babel-preset-stage-2": "^6.24.1", + "browser-sync": "^2.23.6", + "browser-sync-webpack-plugin": "^1.2.0", + "copy-webpack-plugin": "^4.3.1", + "copyfiles": "^1.2.0", + "cross-env": "^5.1.3", + "css-loader": "^0.28.9", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^1.1.5", + "html-webpack-plugin": "^2.30.1", + "laravel-mix": "^1.0", + "lost": "^8.2.0", + "node-sass": "^4.6.1", + "optimize-css-assets-webpack-plugin": "^3.2.0", + "postcss-loader": "^2.0.10", + "react": "^16.2.0", + "react-dom": "^16.2.0", + "react-hot-loader": "^3.1.3", + "redux": "^3.7.2", + "redux-devtools-extension": "^2.13.2", + "resolve-url-loader": "^2.2.1", + "rimraf": "^2.6.2", + "sass-loader": "^6.0.6", + "script-ext-html-webpack-plugin": "^1.8.8", + "style-loader": "^0.19.0", + "svg-url-loader": "^2.3.1", + "uglifyjs-webpack-plugin": "^1.1.6", + "url-loader": "^0.6.2", + "webpack": "^3.8.1", + "webpack-dashboard": "^1.1.1", + "webpack-dev-server": "^2.11.1", + "webpack-manifest-plugin": "^1.3.2", + "webpack-merge": "^4.1.1", + "worker-loader": "^1.1.0" + }, + "stylelint": { + "rules": { + "block-no-empty": null, + "color-no-invalid-hex": true, + "comment-empty-line-before": [ + "always", { + "ignore": [ + "stylelint-commands", + "after-comment" + ] + } + ], + "declaration-colon-space-after": "always", + "indentation": [ + 4, { + "except": [ + "value" + ] + } + ], + "max-empty-lines": 2, + "rule-empty-line-before": [ + "always", { + "except": [ + "first-nested" + ], + "ignore": [ + "after-comment" + ] + } + ], + "unit-whitelist": [ + "em", + "rem", + "%", + "s", + "px" + ] + } + } +} \ No newline at end of file diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100755 index 0000000..8fe95eb --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,25 @@ + + + Coding standard for SilverStripe 3.x + + + */vendor/* + */thirdparty/* + */node_modules/* + + + + + + + + + + + + + + + + + diff --git a/phpunit.xml b/phpunit.xml new file mode 100755 index 0000000..3a1d051 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + cms/tests + framework/tests + + + + + + + + + sanitychecks + + + + diff --git a/robots.txt b/robots.txt new file mode 100755 index 0000000..dfa00d6 --- /dev/null +++ b/robots.txt @@ -0,0 +1,7 @@ +User-agent: * +Allow: / +Crawl-delay: 10 +Disallow: /admin +Disallow: /Security +Sitemap: https://www.bla-bla.org/sitemap.xml +Host: https://www.bla-bla.org \ No newline at end of file diff --git a/site/WebpackTemplateProvider.php b/site/WebpackTemplateProvider.php new file mode 100644 index 0000000..0c94b65 --- /dev/null +++ b/site/WebpackTemplateProvider.php @@ -0,0 +1,90 @@ + 'isActive', + 'WebpackCSS' => 'loadCSS', + 'WebpackJS' => 'loadJS', + ]; + } + + /** + * @var int port number + */ + private static $port = 3000; + + /** + * @var string host name + */ + private static $hostname = 'localhost'; + + /** + * @var string assets static files directory + */ + private static $distDir = 'site/dist'; + + /** + * Load CSS file + * @param $path + */ + public static function loadCSS($path) + { + if (!self::isActive()) { + Requirements::css(self::_toPublicPath($path)); + } + } + + /** + * Load JS file + * @param $path + */ + public static function loadJS($path) + { + $path = self::isActive() ? + self::_toDevServerPath($path) : + self::_toPublicPath($path); + + Requirements::javascript($path); + } + + + /** + * Checks if dev mode is enabled and if webpack server is online + * @return bool + */ + public static function isActive() + { + $class = __CLASS__; + return Director::isDev() && !!@fsockopen( + $class::config()->get('hostname'), + $class::config()->get('port') + ); + } + + protected static function _toDevServerPath($path) + { + $class = __CLASS__; + return sprintf( + 'http://%s:%s/%s', + $class::config()->get('hostname'), + $class::config()->get('port'), + $path + ); + } + + protected static function _toPublicPath($path) + { + $class = __CLASS__; + return $class::config()->get('distDir') . '/' . $path; + } +} diff --git a/site/_config/webpack.yml b/site/_config/webpack.yml new file mode 100644 index 0000000..e610f7a --- /dev/null +++ b/site/_config/webpack.yml @@ -0,0 +1,10 @@ +# that's important to place this file into /site/_config/webpack.yml +# with all configuration variables presented +# Cuz WebPack compiling script use it to set configuration + +WebpackTemplateProvider: + dist: site/dist + hostname: localhost + port: "3000" + pages: site/src/js/types + src: site/src diff --git a/site/src/_config/webpack.yml b/site/src/_config/webpack.yml new file mode 100644 index 0000000..e610f7a --- /dev/null +++ b/site/src/_config/webpack.yml @@ -0,0 +1,10 @@ +# that's important to place this file into /site/_config/webpack.yml +# with all configuration variables presented +# Cuz WebPack compiling script use it to set configuration + +WebpackTemplateProvider: + dist: site/dist + hostname: localhost + port: "3000" + pages: site/src/js/types + src: site/src diff --git a/site/src/favicon.png b/site/src/favicon.png new file mode 100644 index 0000000..966a218 Binary files /dev/null and b/site/src/favicon.png differ diff --git a/site/src/js/_components/_spinner.js b/site/src/js/_components/_spinner.js new file mode 100644 index 0000000..95c3042 --- /dev/null +++ b/site/src/js/_components/_spinner.js @@ -0,0 +1,19 @@ +/** + * Just an example component + */ +import $ from "jquery"; + +const SpinnerUI = (($) => { + class SpinnerUI { + static show(callback) { + $("#PageLoading").show(0, callback); + } + + static hide(callback) { + $("#PageLoading").hide("slow", callback); + } + } + return SpinnerUI; +})($); + +export default SpinnerUI; \ No newline at end of file diff --git a/site/src/js/_events.js b/site/src/js/_events.js new file mode 100644 index 0000000..7f0c0ab --- /dev/null +++ b/site/src/js/_events.js @@ -0,0 +1,8 @@ +/** + * Add your global events here + */ + +module.exports = { + AJAX: "ajax-load", + LOADED: "load" +}; \ No newline at end of file diff --git a/site/src/js/_pageType_and_component_template.js b/site/src/js/_pageType_and_component_template.js new file mode 100644 index 0000000..d2bc62b --- /dev/null +++ b/site/src/js/_pageType_and_component_template.js @@ -0,0 +1,88 @@ +import $ from "jquery"; + +const TypePage = (($) => { + + // Constants + const NAME = "TypePage"; + //const DATA_KEY = "pageUI." + NAME; + + const Events = require("./_events"); + + class TypePage { + // Static methods + static init() { + console.log("Initializing: " + NAME); + } + + static destroy() { + console.log("Destroying: " + NAME); + } + + /** + * jQuery extension functions + // Constructor + constructor(element) { + console.log("Constructing: " + NAME + " elements"); + + this._element = element; + } + + // Public methods + dispose() { + console.log("Disposing: " + NAME + " elements"); + + $.removeData(this._element, DATA_KEY); + this._element = null; + } + + static _jQueryInterface() { + return this.each(function () { + // attach functionality to element + const $element = $(this); + let data = $element.data(DATA_KEY); + + if (!data) { + data = new TypePage(this); + $element.data(DATA_KEY, data); + } + }) + } + */ + } + + $(window).on(Events.AJAX + " " + Events.LOADED, function() { + TypePage.init(); + }); + + // JQuery extension functions + /*$.fn[NAME] = TypePage._jQueryInterface; + $.fn[NAME].Constructor = TypePage; + $.fn[NAME].noConflict = function () { + $.fn[NAME] = JQUERY_NO_CONFLICT; + return TypePage._jQueryInterface; + };*/ + + return TypePage; +})($); + +export default TypePage; + + +/* +import $ from 'jquery'; + +(function (G) { + G.initPulsePage = function () { + G.destroyPulsePage(); + }; + + G.destroyPulsePage = function () {}; + + $(window).on("ajax-content-loaded", function () { + G.initPulsePage(); + }); + + $(document).ready(function () { + G.initPulsePage(); + }); +}(this));*/ \ No newline at end of file diff --git a/site/src/js/app.js b/site/src/js/app.js new file mode 100644 index 0000000..2a20a9a --- /dev/null +++ b/site/src/js/app.js @@ -0,0 +1,38 @@ +// import images +function importAll(r) { + return r.keys().map(r); +} + +const images = importAll(require.context("../img/", false, /\.(png|jpe?g|svg)$/)); + +import "../scss/app.scss"; + +// import Bootstrap +import Popper from "popper.js"; +window.Popper = Popper; +import "bootstrap/js/dist/util"; +import "bootstrap/js/dist/alert"; +import "bootstrap/js/dist/button"; +import "bootstrap/js/dist/carousel"; +import "bootstrap/js/dist/collapse"; +import "bootstrap/js/dist/dropdown"; +import "bootstrap/js/dist/modal"; +import "bootstrap/js/dist/tooltip"; +import "bootstrap/js/dist/popover"; +import "bootstrap/js/dist/scrollspy"; +import "bootstrap/js/dist/tab"; +// + +// import your custom UI components +import "./main.js"; + +// TODO: hot module update +/*const Events = require("./_events"); +if (module.hot) { + module.hot.accept(); + module.hot.addStatusHandler(status => { + if(status === "apply"){ + $(window).trigger(Events.AJAX); + } + }); +}*/ \ No newline at end of file diff --git a/site/src/js/main.js b/site/src/js/main.js new file mode 100644 index 0000000..a0cdb55 --- /dev/null +++ b/site/src/js/main.js @@ -0,0 +1,38 @@ +import $ from "jquery"; + +import Events from "./_events"; +// import an example component +import Spinner from "./_components/_spinner"; + +const MainUI = (($) => { + + // Constants + const NAME = "MainUI"; + + class MainUI { + // Static methods + static init() { + this.destroy(); + console.log("Initializing: " + NAME); + + Spinner.hide(function() { + $("body").addClass("loaded"); + }); + } + + static destroy() { + console.log("Destroying: " + NAME); + Spinner.show(function() { + $("body").removeClass("loaded"); + }); + } + } + + $(window).on(Events.AJAX + " " + Events.LOADED, function() { + MainUI.init(); + }); + + return MainUI; +})($); + +export default MainUI; \ No newline at end of file diff --git a/site/src/scss/_layout.scss b/site/src/scss/_layout.scss new file mode 100644 index 0000000..5ca54d0 --- /dev/null +++ b/site/src/scss/_layout.scss @@ -0,0 +1,7 @@ +/** + * Your custom style + */ + +html,body { + background:#000; +} \ No newline at end of file diff --git a/site/src/scss/_variables.scss b/site/src/scss/_variables.scss new file mode 100644 index 0000000..48a987c --- /dev/null +++ b/site/src/scss/_variables.scss @@ -0,0 +1,10 @@ +/* + * Your custom variables + */ + +// bootstrap minify bugfix: +$navbar-dark-toggler-icon-bg: none; +$navbar-light-toggler-icon-bg: none; + +// IE > 9 +$enable-flex: true; \ No newline at end of file diff --git a/site/src/scss/app.scss b/site/src/scss/app.scss new file mode 100644 index 0000000..c2eda41 --- /dev/null +++ b/site/src/scss/app.scss @@ -0,0 +1,42 @@ +// Your custom variables +@import "variables"; + +// Bootstrap basics +@import "../../../node_modules/bootstrap/scss/functions"; +@import "../../../node_modules/bootstrap/scss/variables"; +@import "../../../node_modules/bootstrap/scss/mixins"; +@import "../../../node_modules/bootstrap/scss/root"; +@import "../../../node_modules/bootstrap/scss/reboot"; +@import "../../../node_modules/bootstrap/scss/type"; +@import "../../../node_modules/bootstrap/scss/images"; +@import "../../../node_modules/bootstrap/scss/code"; +@import "../../../node_modules/bootstrap/scss/grid"; +@import "../../../node_modules/bootstrap/scss/tables"; +@import "../../../node_modules/bootstrap/scss/forms"; +@import "../../../node_modules/bootstrap/scss/buttons"; +@import "../../../node_modules/bootstrap/scss/transitions"; +@import "../../../node_modules/bootstrap/scss/dropdown"; +@import "../../../node_modules/bootstrap/scss/button-group"; +@import "../../../node_modules/bootstrap/scss/input-group"; +@import "../../../node_modules/bootstrap/scss/custom-forms"; +@import "../../../node_modules/bootstrap/scss/nav"; +@import "../../../node_modules/bootstrap/scss/navbar"; +@import "../../../node_modules/bootstrap/scss/card"; +@import "../../../node_modules/bootstrap/scss/breadcrumb"; +@import "../../../node_modules/bootstrap/scss/pagination"; +@import "../../../node_modules/bootstrap/scss/badge"; +@import "../../../node_modules/bootstrap/scss/jumbotron"; +@import "../../../node_modules/bootstrap/scss/alert"; +@import "../../../node_modules/bootstrap/scss/progress"; +@import "../../../node_modules/bootstrap/scss/media"; +@import "../../../node_modules/bootstrap/scss/list-group"; +@import "../../../node_modules/bootstrap/scss/close"; +@import "../../../node_modules/bootstrap/scss/modal"; +@import "../../../node_modules/bootstrap/scss/tooltip"; +@import "../../../node_modules/bootstrap/scss/popover"; +@import "../../../node_modules/bootstrap/scss/carousel"; +@import "../../../node_modules/bootstrap/scss/utilities"; +@import "../../../node_modules/bootstrap/scss/print"; + +// Your custom UI +@import "layout"; \ No newline at end of file diff --git a/site/templates/Page.ss b/site/templates/Page.ss new file mode 100644 index 0000000..23012d1 --- /dev/null +++ b/site/templates/Page.ss @@ -0,0 +1,64 @@ + + +<%-- manifest="/cache.appcache" --%> + + $MetaTags + + + + + + + + + + + + + + + + + + + + + <% base_tag %> + + + + + + + + + + + + + + + + + +
+ +
+ +
+ $Layout +
+ + + +
+ $BetterNavigator +
+ + $WebpackJS('app.js') + $WebpackCSS('app.css') + + + \ No newline at end of file diff --git a/webpack.config.common.js b/webpack.config.common.js new file mode 100755 index 0000000..edbacf8 --- /dev/null +++ b/webpack.config.common.js @@ -0,0 +1,122 @@ +const path = require("path"); +const webpack = require("webpack"); +const ExtractTextPlugin = require("extract-text-webpack-plugin"); +const ManifestPlugin = require("webpack-manifest-plugin"); +const conf = require("./webpack.configuration"); +const isProduction = process.env.NODE_ENV === "production"; + +const jsScripts = { + app: path.join(conf.SRC, "js/app.js"), +}; + +const _getAllFilesFromFolder = function(dir) { + let filesystem = require("fs"); + let results = []; + + filesystem.readdirSync(dir).forEach(function(file) { + + file = dir + "/" + file; + let stat = filesystem.statSync(file); + + if (stat && stat.isDirectory()) { + results = results.concat(_getAllFilesFromFolder(file)) + } else results.push(file); + + }); + + return results; +}; + +// add page specific scripts +const pageScripts = _getAllFilesFromFolder(conf.PAGES); +pageScripts.forEach((file) => { + jsScripts[path.basename(file, ".js")] = file; +}); + +module.exports = { + entry: jsScripts, + devtool: "source-map", + externals: { + "custom-select": "CustomSelect", + "ui-progress-button": "UIProgressButton" + }, + module: { + rules: [{ + test: /\.jsx?$/, + exclude: /node_modules/, + use: { + loader: "babel-loader", + options: { + presets: [ + ["es2015", { + modules: false + }], + ["stage-2"] + ], + plugins: [ + ["transform-react-jsx"], + ["react-hot-loader/babel"], + ] + }, + } + }, { + test: /\.(png|jpg|gif|svg)$/, + loader: "file-loader", + options: { + name: "img/[name].[ext]", + } + }, { + test: /\.eot(\?v=\d+.\d+.\d+)?$/, + use: { + loader: "file-loader", + options: { + name: "fonts/[name].[ext]" + } + } + }, { + test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, + use: { + loader: "url-loader", + options: { + name: "fonts/[name].[ext]", + limit: 10000, + mimetype: "application/font-woff" + } + } + }, { + test: /\.[ot]tf(\?v=\d+.\d+.\d+)?$/, + use: { + loader: "url-loader", + options: { + name: "fonts/[name].[ext]", + limit: 10000, + mimetype: "application/octet-stream" + } + } + }, { + test: /\.worker\.js$/, + use: { + loader: "worker-loader" + } + }] + }, + plugins: [ + new webpack.ProvidePlugin({ + $: "jquery", + jQuery: "jquery", + "window.jQuery": "jquery", + Popper: ["popper.js", "default"], + Util: "exports-loader?Util!bootstrap/js/dist/util", + Alert: "exports-loader?Alert!bootstrap/js/dist/alert", + Button: "exports-loader?Button!bootstrap/js/dist/button", + Carousel: "exports-loader?Carousel!bootstrap/js/dist/carousel", + Collapse: "exports-loader?Collapse!bootstrap/js/dist/collapse", + Dropdown: "exports-loader?Dropdown!bootstrap/js/dist/dropdown", + Modal: "exports-loader?Modal!bootstrap/js/dist/modal", + Tooltip: "exports-loader?Tooltip!bootstrap/js/dist/tooltip", + Popover: "exports-loader?Popover!bootstrap/js/dist/popover", + Scrollspy: "exports-loader?Scrollspy!bootstrap/js/dist/scrollspy", + Tab: "exports-loader?Tab!bootstrap/js/dist/tab", + }) + ], +}; \ No newline at end of file diff --git a/webpack.config.dev.js b/webpack.config.dev.js new file mode 100755 index 0000000..559a12d --- /dev/null +++ b/webpack.config.dev.js @@ -0,0 +1,97 @@ +const autoprefixer = require('autoprefixer'); +const webpack = require('webpack'); +const merge = require('webpack-merge'); +const common = require('./webpack.config.common.js'); +const conf = require('./webpack.configuration'); + +const IP = process.env.IP || conf.HOSTNAME; +const PORT = process.env.PORT || conf.PORT; + +const config = merge.strategy({ + entry: 'prepend' +})(common, { + + entry: { + app: [ + 'react-hot-loader/patch', + 'webpack-dev-server/client?http://' + conf.HOSTNAME + ':' + conf.PORT + '/', + 'webpack/hot/only-dev-server', + ], + main: [ + 'webpack-dev-server/client?http://' + conf.HOSTNAME + ':' + conf.PORT + '/', + 'webpack/hot/only-dev-server', + ], + }, + + output: { + path: conf.BUILD, + filename: '[name].js', + // necessary for HMR to know where to load the hot update chunks + publicPath: 'http://' + conf.HOSTNAME + ':' + conf.PORT + '/' + }, + + module: { + rules: [{ + test: /\.scss$/, + use: [{ + loader: 'style-loader', + options: { + sourceMap: true + } + }, { + loader: 'css-loader', + options: { + sourceMap: true + } + }, { + loader: 'postcss-loader', + options: { + sourceMap: true, + plugins: [ + autoprefixer({ + // If we want to use the same browser list for more tools + // this list should be moved to package.json + // https://evilmartians.com/chronicles/autoprefixer-7-browserslist-2-released + browsers: [ + 'ie >= 11', + 'ie_mob >= 11', + 'Safari >= 10', + 'Android >= 4.4', + 'Chrome >= 44', // Retail + 'Samsung >= 4' + ] + }), + // http://lostgrid.org/docs.html + require('lost') + ] + } + }, { + loader: 'sass-loader', + options: { + sourceMap: true + } + }, ] + }, ] + }, + plugins: [ + new webpack.NamedModulesPlugin(), + new webpack.HotModuleReplacementPlugin(), + new webpack.NoEmitOnErrorsPlugin(), + ], + + devServer: { + host: IP, + port: PORT, + historyApiFallback: true, + hot: true, + overlay: { + warnings: true, + errors: true + }, + headers: { + 'Access-Control-Allow-Origin': '*' + } + }, +}); + +module.exports = config; \ No newline at end of file diff --git a/webpack.config.prod.js b/webpack.config.prod.js new file mode 100755 index 0000000..cedee69 --- /dev/null +++ b/webpack.config.prod.js @@ -0,0 +1,102 @@ +const path = require('path'); +const autoprefixer = require('autoprefixer'); +const webpack = require('webpack'); +const merge = require('webpack-merge'); +const common = require('./webpack.config.common.js'); +const OptimizeCSSAssets = require('optimize-css-assets-webpack-plugin'); +const conf = require('./webpack.configuration'); +const ExtractTextPlugin = require("extract-text-webpack-plugin"); +const FaviconsWebpackPlugin = require("favicons-webpack-plugin"); +const fs = require("fs"); +const yaml = require("js-yaml"); +const confYML = yaml.safeLoad(fs.readFileSync(path.join(__dirname, "site/_config/webpack.yml"), "utf8")); + +module.exports = merge(common, { + + output: { + path: conf.BUILD, + filename: '[name].js', + publicPath: confYML.WebpackTemplateProvider.dist + '/', + }, + + module: { + rules: [{ + test: /\.scss$/, + use: ExtractTextPlugin.extract({ + fallback: "style-loader", + use: [{ + loader: 'css-loader', + options: { + sourceMap: true + } + }, { + loader: 'postcss-loader', + options: { + sourceMap: true, + plugins: [ + autoprefixer({ + // If we want to use the same browser list for more tools + // this list should be moved to package.json + // https://evilmartians.com/chronicles/autoprefixer-7-browserslist-2-released + browsers: [ + 'ie >= 11', + 'ie_mob >= 11', + 'Safari >= 10', + 'Android >= 4.4', + 'Chrome >= 44', // Retail + 'Samsung >= 4' + ] + }), + // http://lostgrid.org/docs.html + require('lost') + ] + } + }, { + loader: 'resolve-url-loader' + }, { + loader: 'sass-loader', + options: { + sourceMap: true + } + }, ] + }) + }, ] + }, + + plugins: [ + + new webpack.DefinePlugin({ + 'process.env': { + 'NODE_ENV': JSON.stringify('production') + } + }), + + new webpack.optimize.ModuleConcatenationPlugin(), + new webpack.optimize.UglifyJsPlugin({ + sourceMap: true, + comments: false + }), + new ExtractTextPlugin({ + filename: '[name].css', + allChunks: true + }), + new OptimizeCSSAssets(), + new FaviconsWebpackPlugin({ + logo: conf.SRC + '/favicon.png', + prefix: '/icons/', + statsFilename: confYML.WebpackTemplateProvider.dist + '/icons/iconstats.json', + icons: { + android: true, + appleIcon: true, + appleStartup: true, + coast: true, + favicons: true, + firefox: true, + opengraph: true, + twitter: true, + yandex: true, + windows: true + } + }), + ], +}); \ No newline at end of file diff --git a/webpack.configuration.js b/webpack.configuration.js new file mode 100755 index 0000000..6921736 --- /dev/null +++ b/webpack.configuration.js @@ -0,0 +1,12 @@ +const path = require("path"); +const fs = require("fs"); +const yaml = require("js-yaml"); +const conf = yaml.safeLoad(fs.readFileSync(path.join(__dirname, "site/_config/webpack.yml"), "utf8")); + +module.exports = { + SRC: path.join(__dirname, conf.WebpackTemplateProvider.src), + BUILD: path.join(__dirname, conf.WebpackTemplateProvider.dist), + PAGES: path.join(__dirname, conf.WebpackTemplateProvider.pages), + HOSTNAME: conf.WebpackTemplateProvider.hostname, + PORT: conf.WebpackTemplateProvider.port +}; \ No newline at end of file