diff --git a/bin/app/App.js b/bin/app/App.js index 40a7812..b3feac7 100644 --- a/bin/app/App.js +++ b/bin/app/App.js @@ -8,6 +8,21 @@ import SampleContainer from "./components/SampleContainer"; const muiTheme = createMuiTheme({}); +if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker + .register("sw.js") + .then(reg => { + console.log("ServiceWorker is registered.", reg); + }) + .catch(err => { + console.log("ServiceWorker registration error.", err); + }); + }); +} else { + console.log("Your browser doesn't suppert ServiceWorker.", navigator); +} + render( diff --git a/bin/app/components/Content.js b/bin/app/components/Content.js deleted file mode 100644 index 422b137..0000000 --- a/bin/app/components/Content.js +++ /dev/null @@ -1,29 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import Button from "@material-ui/core/Button"; -import SampleActionCreators from "../actions/SampleActionCreators"; - -class Content extends Component { - handleClick = e => { - SampleActionCreators.actionCreator001(); - }; - - render() { - return ( -
-

{this.props.title}

-

{this.props.subtitle}

-
{this.props.text}
- -
- ); - } -} - -Content.propTypes = { - title: PropTypes.string.isRequired, - subtitle: PropTypes.string.isRequired, - text: PropTypes.string.isRequired -}; - -export default Content; diff --git a/bin/app/components/Menu.js b/bin/app/components/Menu.js deleted file mode 100644 index 92177c6..0000000 --- a/bin/app/components/Menu.js +++ /dev/null @@ -1,31 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import { Link } from "react-router-dom"; -import ListSubheader from "@material-ui/core/ListSubheader"; -import List from "@material-ui/core/List"; -import ListItem from "@material-ui/core/ListItem"; -import Drawer from "@material-ui/core/Drawer"; - -class Menu extends Component { - render() { - return ( - - - Menu - - Top - - - Sample - - - - ); - } -} - -Menu.propTypes = { - width: PropTypes.number -}; - -export default Menu; diff --git a/bin/app/components/Navi.js b/bin/app/components/Navi.js index 7f49028..e1a4545 100644 --- a/bin/app/components/Navi.js +++ b/bin/app/components/Navi.js @@ -1,25 +1,60 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import AppBar from '@material-ui/core/AppBar'; -import Toolbar from '@material-ui/core/Toolbar'; -import Typography from '@material-ui/core/Typography'; +import React, { useState } from "react"; -class Navi extends Component { - render() { - return ( - +import AppBar from "@material-ui/core/AppBar"; +import Toolbar from "@material-ui/core/Toolbar"; +import Typography from "@material-ui/core/Typography"; + +import ListSubheader from "@material-ui/core/ListSubheader"; +import List from "@material-ui/core/List"; +import ListItem from "@material-ui/core/ListItem"; +import Drawer from "@material-ui/core/Drawer"; + +import IconButton from "@material-ui/core/IconButton"; +import MenuIcon from "@material-ui/icons/Menu"; + +import { Link } from "react-router-dom"; + +const Navi = ({ title }) => { + const [isOpen, setOpen] = useState(false); + return ( + <> + - - {this.props.title} - + setOpen(!isOpen)}> + + +
+ {title} +
- ); - } -} - -Navi.propTypes = { - title: PropTypes.string.isRequired, -} + setOpen(false)}> + + Menu + + Top + + + Sample + + + + + ); +}; export default Navi; diff --git a/bin/app/html/favicon.ico b/bin/app/html/favicon.ico new file mode 100644 index 0000000..5c125de Binary files /dev/null and b/bin/app/html/favicon.ico differ diff --git a/bin/app/html/index.html b/bin/app/html/index.html new file mode 100644 index 0000000..af047db --- /dev/null +++ b/bin/app/html/index.html @@ -0,0 +1,17 @@ + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + +
+ + diff --git a/bin/app/icon/icon.png b/bin/app/icon/icon.png new file mode 100644 index 0000000..7fa0575 Binary files /dev/null and b/bin/app/icon/icon.png differ diff --git a/bin/app/sw.js b/bin/app/sw.js new file mode 100644 index 0000000..872d795 --- /dev/null +++ b/bin/app/sw.js @@ -0,0 +1,65 @@ +console.log(`${new Date()}: Service Worker is loaded`); + +// Set cache name for multiple projects. +// @see https://developers.google.com/web/tools/workbox/modules/workbox-core +workbox.core.setCacheNameDetails({ + prefix: "starter-react-flux", + suffix: "v1", + precache: "install-time", + runtime: "run-time", + googleAnalytics: "ga" +}); + +workbox.core.skipWaiting(); +workbox.core.clientsClaim(); + +// Enable google analytics for offline +// @see https://developers.google.com/web/tools/workbox/modules/workbox-google-analytics +// workbox.googleAnalytics.initialize(); + +workbox.precaching.precacheAndRoute(self.__precacheManifest); + +// Cache Google Fonts +workbox.routing.registerRoute( + "https://fonts.googleapis.com/(.*)", + new workbox.strategies.CacheFirst({ + cacheName: "google-fonts", + cacheableResponse: { statuses: [0, 200] } + }) +); + +// Static content from Google +workbox.routing.registerRoute( + /.*(?:gstatic)\.com.*$/, + new workbox.strategies.CacheFirst({ + cacheName: "google-static" + }) +); + +// Cache any images which are included the extention list +workbox.routing.registerRoute( + /\.(?:png|gif|jpg|svg)$/, + new workbox.strategies.CacheFirst({ + cacheName: "image-content", + cacheableResponse: { statuses: [0, 200] } + }) +); + +// Cache any JavaScript and CSS which are included the extention list +workbox.routing.registerRoute( + /\.(?:js|css)$/, + new workbox.strategies.StaleWhileRevalidate({ + cacheName: "static-resources", + cacheableResponse: { statuses: [0, 200] } + }) +); + +// Cache any HTTP Content +workbox.routing.registerRoute( + /^http.*/, + new workbox.strategies.StaleWhileRevalidate({ + cacheName: "http-content", + cacheableResponse: { statuses: [0, 200] } + }), + "GET" +); diff --git a/bin/app/webpack.common.js b/bin/app/webpack.common.js new file mode 100644 index 0000000..902190a --- /dev/null +++ b/bin/app/webpack.common.js @@ -0,0 +1,50 @@ +const webpack = require("webpack"); +const path = require("path"); +const { InjectManifest } = require("workbox-webpack-plugin"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const WebpackPwaManifest = require("webpack-pwa-manifest"); + +const config = { + entry: path.resolve(__dirname, "app/App.js"), + output: { + path: path.resolve(__dirname, "public"), + filename: "bundle.js" + }, + module: { + rules: [ + { + test: /.jsx?$/, + exclude: [path.resolve(__dirname, "node_modules")], + loader: "babel-loader" + } + ] + }, + plugins: [ + new HtmlWebpackPlugin({ + template: "./app/html/index.html", + title: "Starter-React-Flux" + }), + new InjectManifest({ + swSrc: path.resolve(__dirname, "app", "sw.js"), + swDest: path.resolve(__dirname, "public", "sw.js") + }), + new WebpackPwaManifest({ + name: "PWA by Starter-React-Flux", + short_name: "SRF-PWA", + description: "A Progressive Web App generated by Starter-React-Flux", + background_color: "#ffffff", + inject: true, + fingerprints: true, + ios: true, + crossorigin: null, + icons: [ + { + src: path.resolve("app/icon/icon.png"), + sizes: [96, 128, 192, 256, 384, 512, 1024] + } + ] + }) + ] +}; + +module.exports = config; diff --git a/bin/app/webpack.dev.js b/bin/app/webpack.dev.js new file mode 100644 index 0000000..fed1425 --- /dev/null +++ b/bin/app/webpack.dev.js @@ -0,0 +1,16 @@ +const merge = require("webpack-merge"); +const common = require("./webpack.common.js"); +const path = require("path"); + +const config = { + mode: "development", + devtool: "inline-source-map", + devServer: { + contentBase: path.resolve(__dirname, "public"), + historyApiFallback: true, + compress: true, + open: true + } +}; + +module.exports = merge(common, config); diff --git a/bin/app/webpack.js b/bin/app/webpack.js deleted file mode 100644 index 9e62bbc..0000000 --- a/bin/app/webpack.js +++ /dev/null @@ -1,29 +0,0 @@ -const webpack = require("webpack"); -const path = require("path"); - -const config = { - mode: "production", - entry: path.resolve(__dirname, "app/App.js"), - output: { - path: path.resolve(__dirname, "public/js/"), - publicPath: "/js/", - filename: "bundle.js" - }, - module: { - rules: [ - { - test: /.jsx?$/, - exclude: [path.resolve(__dirname, "node_modules")], - loader: "babel-loader" - } - ] - }, - devServer: { - contentBase: path.resolve(__dirname, "public"), - historyApiFallback: true, - compress: true, - open: true - } -}; - -module.exports = config; diff --git a/bin/app/webpack.prod.js b/bin/app/webpack.prod.js new file mode 100644 index 0000000..3e667e9 --- /dev/null +++ b/bin/app/webpack.prod.js @@ -0,0 +1,20 @@ +const merge = require("webpack-merge"); +const common = require("./webpack.common.js"); +const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") + .BundleAnalyzerPlugin; +const WebpackBundleSizeAnalyzerPlugin = require("webpack-bundle-size-analyzer") + .WebpackBundleSizeAnalyzerPlugin; + +const config = { + mode: "production", + plugins: [ + new BundleAnalyzerPlugin({ + analyzerMode: "static", + openAnalyzer: true, + reportFilename: "../analysis/bundle-analyzer.html" + }), + new WebpackBundleSizeAnalyzerPlugin("../analysis/bundle-size-analyzer.log") + ] +}; + +module.exports = merge(common, config); diff --git a/bin/generator.js b/bin/generator.js index b20c4c8..ab085a1 100644 --- a/bin/generator.js +++ b/bin/generator.js @@ -1,55 +1,117 @@ -const fs = require('fs'); -const util = require('util'); -const path = require('path'); -const fu = require('./futil'); - -module.exports.ComponentFile = (name) => { - const code = -`import React, { Component } from 'react'; +const fs = require("fs"); +const util = require("util"); +const path = require("path"); +const fu = require("./futil"); + +module.exports.ContentFile = contentPrefix => { + const code = `import React from 'react'; import PropTypes from 'prop-types'; +import Button from "@material-ui/core/Button"; +import ${contentPrefix}ActionCreators from "../actions/${contentPrefix}ActionCreators"; -class ${name} extends Component { - render() { - return ( -
-

{this.props.title}

-

{this.props.subtitle}

-
{this.props.text}
+const ${contentPrefix}Content = ({ title, subtitle, text }) => { + const handleClick = () => { + ${contentPrefix}ActionCreators.actionCreator001(); + }; + + return ( +
+
+
+ Starter React Flux +
+
+ Superfast React development tool +
- ); - } -} +
+
+ {title} +
+
+ {subtitle} +
+
+ {text} +
+ +
+
+ ); +}; -${name}.propTypes = { +${contentPrefix}Content.propTypes = { title: PropTypes.string.isRequired, subtitle: PropTypes.string.isRequired, text: PropTypes.string.isRequired } -export default ${name}; +export default ${contentPrefix}Content; `; - - fu.createFile(`./app/components/${name}.js`, code); -} + fu.createFile(`./app/components/${contentPrefix}Content.js`, code); +}; -module.exports.ContainerFile = (name) => { - const code = -`import React, { Component } from 'react'; +module.exports.ContainerFile = prefix => { + const code = `import React, { Component } from 'react'; import { Container } from 'flux/utils'; -import SampleStore from '../stores/SampleStore'; +import ${prefix}Store from '../stores/${prefix}Store'; import Navi from './Navi'; -import Menu from './Menu'; -import Content from './Content'; +import ${prefix}Content from './${prefix}Content'; -class ${name}Container extends Component { +class ${prefix}Container extends Component { static getStores() { - return [SampleStore]; + return [${prefix}Store]; } static calculateState() { return { - sample: SampleStore.getState() + data: ${prefix}Store.getState() }; } @@ -58,37 +120,30 @@ class ${name}Container extends Component { render() { return ( -
- -
- - -
-
+ <> + + <${prefix}Content + title={this.state.data.title} + subtitle={this.state.data.subtitle} + text={this.state.data.text} + /> + ); } } -export default Container.create(${name}Container); +export default Container.create(${prefix}Container); `; - fu.createFile(`./app/components/${name}Container.js`, code); -} - - -module.exports.StoreFile = (name) => { + fu.createFile(`./app/components/${prefix}Container.js`, code); +}; - const code = -`import { ReduceStore } from 'flux/utils'; +module.exports.StoreFile = prefix => { + const code = `import { ReduceStore } from 'flux/utils'; import ActionTypes from '../constants/AppConstants'; import AppDispatcher from '../dispatcher/AppDispatcher'; -class ${name}Store extends ReduceStore { +class ${prefix}Store extends ReduceStore { getInitialState() { return { title: "Title", @@ -102,13 +157,12 @@ class ${name}Store extends ReduceStore { switch (action.type) { case ActionTypes.TYPE_001: const newCount = state.count + 1; - const result = { + return { title: action.data.title, subtitle: action.data.subtitle, - text: "Action Creator is called " + newCount + " times.", + text: "Action Creator was called " + newCount + " times.", count: newCount } - return result; case ActionTypes.TYPE_002: return state; default: @@ -117,27 +171,24 @@ class ${name}Store extends ReduceStore { } } -export default new ${name}Store(AppDispatcher); +export default new ${prefix}Store(AppDispatcher); `; - fu.createFile(`./app/stores/${name}Store.js`, code); -} - - -module.exports.ActionFile = (name) => { + fu.createFile(`./app/stores/${prefix}Store.js`, code); +}; - const code = -`import AppDispatcher from '../dispatcher/AppDispatcher'; +module.exports.ActionFile = prefix => { + const code = `import AppDispatcher from '../dispatcher/AppDispatcher'; import ActionTypes from '../constants/AppConstants'; -const ${name}ActionCreators = { +const ${prefix}ActionCreators = { actionCreator001(arg) { AppDispatcher.dispatch({ - type: ActionTypes.TYPE_001, + type: ActionTypes.${prefix}_TYPE_001, data: { "title": "New Title", - "subtitle": "New Subtitle", - "text": "New Text" + "subtitle": "Created by ActionCreator", + "text": "This text will be overwritten" }, }); }, @@ -146,46 +197,63 @@ const ${name}ActionCreators = { // 2. Create an action from the result. // 3, Pass the action to the dispatch(). AppDispatcher.dispatch({ - type: ActionTypes.TYPE_002, + type: ActionTypes.${prefix}_TYPE_002, data: 'RESULT OF YOUT ACTION', }); }, }; -export default ${name}ActionCreators; +export default ${prefix}ActionCreators; `; - fu.createFile(`./app/actions/${name}ActionCreators.js`, code); -} + fu.createFile(`./app/actions/${prefix}ActionCreators.js`, code); +}; + +module.exports.AppConstantFile = prefixList => { + const types = prefixList + .map( + x => ` + ${x.toUpperCase()}_TYPE_001: '${x.toUpperCase()}_TYPE_001', + ${x.toUpperCase()}_TYPE_002: '${x.toUpperCase()}_TYPE_002',` + ) + .reduce((p, c) => p + c, ""); + + const code = `const ActionTypes = { +${types} -module.exports.ComponentTestFiles = () => { - const basePath = './app/components/'; - const components = fu.getFileNames(basePath); - for (const i in components) { - const component = path.parse(components[i]).name; - const testFile = './__tests__/' + component + '-test.js'; - fu.createFile(testFile, generator.ComponentTestCode(component)); } -} -module.exports.ComponentTestCode = (module) => { - const testCode = -`import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestUtils from 'react-dom/test-utils'; -import ${module} from '../app/components/${module}' + export default ActionTypes; +`; -test('${module} is equeal to ...' , () => { - const app = ReactTestUtils.renderIntoDocument( - <${module} /> - ); - const appNode = ReactDOM.findDOMNode(app); - expect('hello').toequeal('hello'); - //expect(appNode.//todo).toEqual('//todo'); + fu.createFile(`./app/constants/AppConstants.js`, code); +}; + +module.exports.ContentTestCode = prefix => { + const code = `import React from "react"; +import renderer from "react-test-renderer"; +import ${prefix}Content from "../app/components/${prefix}Content"; +test("Check the content", () => { + const component = renderer.create( + <${prefix}Content title="Title" subtitle="Subtitle" text="Text" /> + ); + const instance = component.root; + expect(instance.findByProps({ className: "hero-title" }).children).toEqual([ + "Starter React Flux" + ]); + expect(instance.findByProps({ className: "hero-subtitle" }).children).toEqual( + ["Superfast React development tool"] + ); + //instance.findByProps({ className: "button" }).props.onClick(); }); -` - return testCode; -} +test("Snapshot testing", () => { + const component = renderer.create( + <${prefix}Content title="Title" subtitle="Subtitle" text="Text" /> + ); + expect(component.toJSON()).toMatchSnapshot(); +});`; + fu.createFile(`./__tests__/${prefix}Content-test.js`, code); +}; diff --git a/bin/index.js b/bin/index.js index 049dd27..885eb88 100755 --- a/bin/index.js +++ b/bin/index.js @@ -14,15 +14,19 @@ const dirs = [ "./app/dispatcher", "./app/stores", "./app/utils", + "./app/html", + "./app/icon", // Build "./public", "./public/css", "./public/img", - "./public/js", // Jest - "./__tests__" + "./__tests__", + + // Bundle analysis + "./analysis/" ]; const npms = [ @@ -32,33 +36,32 @@ const npms = [ "yarn add --dev @babel/preset-env", "yarn add --dev @babel/preset-react", - // Stage 0 - "yarn add --dev @babel/plugin-proposal-function-bind", + // Polyfill + "yarn add @babel/runtime", + "yarn add --dev @babel/plugin-transform-runtime", - // Stage 1 + // Experimental + "yarn add --dev @babel/plugin-proposal-class-properties", + "yarn add --dev @babel/plugin-proposal-decorators", + "yarn add --dev @babel/plugin-proposal-do-expressions", "yarn add --dev @babel/plugin-proposal-export-default-from", + "yarn add --dev @babel/plugin-proposal-export-namespace-from", + "yarn add --dev @babel/plugin-proposal-function-bind", + "yarn add --dev @babel/plugin-proposal-function-sent", "yarn add --dev @babel/plugin-proposal-logical-assignment-operators", - "yarn add --dev @babel/plugin-proposal-optional-chaining", - "yarn add --dev @babel/plugin-proposal-pipeline-operator", "yarn add --dev @babel/plugin-proposal-nullish-coalescing-operator", - "yarn add --dev @babel/plugin-proposal-do-expressions", - - // Stage 2 - "yarn add --dev @babel/plugin-proposal-decorators", - "yarn add --dev @babel/plugin-proposal-function-sent", - "yarn add --dev @babel/plugin-proposal-export-namespace-from", "yarn add --dev @babel/plugin-proposal-numeric-separator", + "yarn add --dev @babel/plugin-proposal-optional-chaining", + "yarn add --dev @babel/plugin-proposal-pipeline-operator", + "yarn add --dev @babel/plugin-proposal-private-methods", "yarn add --dev @babel/plugin-proposal-throw-expressions", - // Stage 3 + // Others "yarn add --dev @babel/plugin-syntax-dynamic-import", "yarn add --dev @babel/plugin-syntax-import-meta", - "yarn add --dev @babel/plugin-proposal-class-properties", "yarn add --dev @babel/plugin-proposal-json-strings", - "yarn add --dev @babel/plugin-transform-runtime", - - // React.js + // React "yarn add react@next", "yarn add react-dom@next", "yarn add prop-types@next", @@ -72,15 +75,21 @@ const npms = [ // Jest "yarn add --dev jest-cli", "yarn add --dev babel-jest", - "yarn add --dev babel-core@^7.0.0-0", - "yarn add --dev regenerator-runtime", + "yarn add --dev react-test-renderer", // WebPack "yarn add --dev webpack", "yarn add --dev webpack-cli", "yarn add --dev webpack-dev-server", - "yarn add --dev webpack-bundle-analyzer", "yarn add --dev babel-loader", + "yarn add --dev webpack-merge", + // Analyze modules + "yarn add --dev webpack-bundle-analyzer", + "yarn add --dev webpack-bundle-size-analyzer", + // For PWA + "yarn add --dev workbox-webpack-plugin", + "yarn add --dev webpack-pwa-manifest", + "yarn add --dev html-webpack-plugin", // ESLint "yarn add --dev eslint", @@ -121,14 +130,12 @@ const jest = { }; const scripts = { - start: "webpack-dev-server --progress --colors --mode development", - dev: "webpack -p --progress --colors --mode development", - build: "webpack -p --progress --colors --mode production", + start: "webpack-dev-server --progress --colors --config webpack.dev.js", + build: "webpack -p --progress --colors --config webpack.prod.js", test: "jest", + update_test: "jest --updateSnapshot", lint: "eslint app/** __tests__/**", - fix: "eslint app/** __tests__/** --fix", - "bundle-analyze": - "webpack --profile --json > stats.json && webpack-bundle-analyzer ./stats.json" + fix: "eslint app/** __tests__/** --fix" }; const eslint = { @@ -244,61 +251,86 @@ function setupReact(arg) { fu.createJSON(".eslintrc", eslint); fu.createJSON(".babelrc", { - presets: ["@babel/preset-react", "@babel/preset-env"], + presets: [ + "@babel/preset-react", + [ + "@babel/preset-env", + { + targets: [ + "last 2 Chrome versions", + "last 2 Safari versions", + "last 2 Firefox versions", + "ie 11", + "cover 85% in US" + ] + } + ] + ], plugins: [ - "@babel/plugin-transform-runtime", - "@babel/plugin-proposal-function-bind", + ["@babel/plugin-proposal-class-properties", { loose: false }], + ["@babel/plugin-proposal-decorators", { legacy: true }], + "@babel/plugin-proposal-do-expressions", "@babel/plugin-proposal-export-default-from", + "@babel/plugin-proposal-export-namespace-from", + "@babel/plugin-proposal-function-bind", + "@babel/plugin-proposal-function-sent", "@babel/plugin-proposal-logical-assignment-operators", - ["@babel/plugin-proposal-optional-chaining", { loose: false }], - ["@babel/plugin-proposal-pipeline-operator", { proposal: "minimal" }], ["@babel/plugin-proposal-nullish-coalescing-operator", { loose: false }], - "@babel/plugin-proposal-do-expressions", - ["@babel/plugin-proposal-decorators", { legacy: true }], - "@babel/plugin-proposal-function-sent", - "@babel/plugin-proposal-export-namespace-from", "@babel/plugin-proposal-numeric-separator", + ["@babel/plugin-proposal-optional-chaining", { loose: false }], + ["@babel/plugin-proposal-pipeline-operator", { proposal: "minimal" }], + ["@babel/plugin-proposal-private-methods", { loose: false }], "@babel/plugin-proposal-throw-expressions", "@babel/plugin-syntax-dynamic-import", "@babel/plugin-syntax-import-meta", - ["@babel/plugin-proposal-class-properties", { loose: false }], - "@babel/plugin-proposal-json-strings" + "@babel/plugin-proposal-json-strings", + "@babel/plugin-transform-runtime" ] }); + console.log(__dirname); - fu.createFile("./public/index.html", fu.readFile("./public/index.html")); - fu.createFile("./public/css/style.css", fu.readFile("./public/main.css")); - fu.createFile("webpack.config.js", fu.readFile("./app/webpack.js")); + fu.createFile("./app/html/index.html", fu.readFile("./app/html/index.html")); + fu.createFile("./public/favicon.ico", fu.readFile("./app/html/favicon.ico")); + + fu.createFile("./app/icon/icon.png", fu.readFile("./app/icon/icon.png")); + fu.createFile( + "./public/css/style.css", + fu.readFile("./public/css/style.css") + ); + fu.createFile( + "./public/img/hero.jpeg", + fu.readFile("./public/img/hero.jpeg") + ); + fu.createFile("webpack.common.js", fu.readFile("./app/webpack.common.js")); + fu.createFile("webpack.dev.js", fu.readFile("./app/webpack.dev.js")); + fu.createFile("webpack.prod.js", fu.readFile("./app/webpack.prod.js")); + + fu.createFile("./app/sw.js", fu.readFile("./app/sw.js")); + fu.createFile("./app/App.js", fu.readFile("./app/App.js")); fu.createFile( "./app/dispatcher/AppDispatcher.js", fu.readFile("./app/dispatcher/dispatcher.js") ); - fu.createFile( - "./app/constants/AppConstants.js", - fu.readFile("./app/constants/constant.js") - ); fu.createFile( "./app/components/Navi.js", fu.readFile("./app/components/Navi.js") ); - fu.createFile( - "./app/components/Menu.js", - fu.readFile("./app/components/Menu.js") - ); - fu.createFile( - "./app/components/Content.js", - fu.readFile("./app/components/Content.js") - ); - fu.createFile( - "./__tests__/Content-test.js", - fu.readFile("./__tests__/Content-test.js") - ); - generator.StoreFile("Sample"); - generator.ActionFile("Sample"); generator.ContainerFile("Top"); + generator.ContentFile("Top"); + generator.ContentTestCode("Top"); + generator.ActionFile("Top"); + generator.StoreFile("Top"); + generator.ContainerFile("Sample"); + generator.ContentFile("Sample"); + generator.ContentTestCode("Sample"); + generator.ActionFile("Sample"); + generator.StoreFile("Sample"); + + generator.AppConstantFile(["Top", "Sample"]); + npmInstall(npms); } diff --git a/bin/public/css/style.css b/bin/public/css/style.css new file mode 100644 index 0000000..1acc931 --- /dev/null +++ b/bin/public/css/style.css @@ -0,0 +1,7 @@ +html { + font-family: "Montserrat", sans-serif; +} + +body { + margin: 0; +} diff --git a/bin/public/img/hero.jpeg b/bin/public/img/hero.jpeg new file mode 100644 index 0000000..d0c5b01 Binary files /dev/null and b/bin/public/img/hero.jpeg differ diff --git a/bin/public/index.html b/bin/public/index.html deleted file mode 100644 index 718a526..0000000 --- a/bin/public/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - -
-
- - - diff --git a/bin/public/main.css b/bin/public/main.css deleted file mode 100644 index 944a3de..0000000 --- a/bin/public/main.css +++ /dev/null @@ -1,8 +0,0 @@ -html { - font-family: 'Roboto', sans-serif; -} - -body { - margin: 0; -} - diff --git a/package.json b/package.json index 529afc0..31ad8d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "starter-react-flux", - "version": "3.6.0", + "version": "4.0.0", "private": false, "preferGlobal": true, "scripts": { @@ -23,15 +23,21 @@ "url": "https://github.com/SokichiFujita/starter-react-flux" }, "keywords": [ - "react", - "react.js", + "React", + "React.js", "flux", "flux-utils", + "Progressive Web App", + "PWA", + "ServiceWorker", + "SPA", + "Single Page Application", "jest", "immutable.js", "material-ui", "react-router", "boilerplate", + "create-react-app", "generator", "webpack", "babel",