diff --git a/packages/generator-fluxible/README.md b/packages/generator-fluxible/README.md
index 2e30552d..932f46ac 100644
--- a/packages/generator-fluxible/README.md
+++ b/packages/generator-fluxible/README.md
@@ -20,21 +20,19 @@ Finally, initiate the generator:
yo fluxible
```
-During development, execute `npm run dev` to initiate webpack-dev-server
-(with react-hot-loader support) and your application's server using nodemon.
-Browse to `http://localhost:3000` to see a very simple Fluxible site with
+During development, execute `npm run dev` to initiate webpack-dev-server
+(with react-hot-loader support) and your application's server using nodemon.
+Browse to `http://localhost:3000` to see a very simple Fluxible site with
server-side rendering and client-side navigation. When you change files,
-the client will be hot-reloaded (with the exception of stores) and your
-application server will restart so that you can see the server-side changes
-on the next refresh.
+the server will be reloaded and the bundle will be rebuilt.
-For other environments, make sure your application is built using
+For other environments, make sure your application is built using
`npm run build` and then run `npm start`.
## Debugging
-Fluxible uses [debug](https://www.npmjs.com/package/debug) to expose debugging
-information on the server and client.
+Fluxible uses [debug](https://www.npmjs.com/package/debug) to expose debugging
+information on the server and client.
### Server
@@ -42,6 +40,6 @@ Start the application with the `DEBUG` environment variable: `DEBUG=* grunt`.
### Client
-`fluxibleDebug` is exposed to the `window` object to manage debugging. You can
-enable it via the browser console: `fluxibleDebug.enable('*');` then refresh
+`fluxibleDebug` is exposed to the `window` object to manage debugging. You can
+enable it via the browser console: `fluxibleDebug.enable('*');` then refresh
the page. To disable, type the following: `fluxibleDebug.disable();`.
diff --git a/packages/generator-fluxible/app/index.js b/packages/generator-fluxible/app/index.js
index 776b7ab6..1bc65149 100644
--- a/packages/generator-fluxible/app/index.js
+++ b/packages/generator-fluxible/app/index.js
@@ -41,11 +41,9 @@ module.exports = yeoman.generators.Base.extend({
writing: {
config: function () {
- this.template('.babelrc', '.babelrc', this.context);
- this.template('.editorconfig', '.editorconfig', this.context);
+ this.template('babel.config.js', 'babel.config.js', this.context);
// .gitignore is renamed by npm to .npmignore, so use underscore
this.template('_gitignore', '.gitignore', this.context);
- this.template('.eslintrc', '.eslintrc', this.context);
this.template('package.json', 'package.json', this.context);
},
@@ -53,16 +51,11 @@ module.exports = yeoman.generators.Base.extend({
this.template('app.js', 'app.js', this.context);
this.template('client.js', 'client.js', this.context);
this.template('server.js', 'server.js', this.context);
- this.template('start.js', 'start.js', this.context);
this.template('webpack.config.js', 'webpack.config.js', this.context);
- this.template('webpack.config.production.js', 'webpack.config.production.js', this.context);
- this.template('webpack-dev-server.js', 'webpack-dev-server.js', this.context);
this.directory('actions', 'actions', this.context);
this.directory('components', 'components', this.context);
this.directory('configs', 'configs', this.context);
this.directory('stores', 'stores', this.context);
- // Webpack dev server needs this folder to exist before starting
- this.template('_buildgitignore', 'build/js/.gitignore', this.context);
}
},
diff --git a/packages/generator-fluxible/app/templates/.babelrc b/packages/generator-fluxible/app/templates/.babelrc
deleted file mode 100644
index d4e5f8d4..00000000
--- a/packages/generator-fluxible/app/templates/.babelrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "presets": ["es2015", "react"]
-}
diff --git a/packages/generator-fluxible/app/templates/.editorconfig b/packages/generator-fluxible/app/templates/.editorconfig
deleted file mode 100644
index 2536d66b..00000000
--- a/packages/generator-fluxible/app/templates/.editorconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-# http://editorconfig.org
-root = true
-
-[*]
-indent_style = space
-indent_size = 4
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
-
-[*.md]
-trim_trailing_whitespace = false
diff --git a/packages/generator-fluxible/app/templates/.eslintrc b/packages/generator-fluxible/app/templates/.eslintrc
deleted file mode 100644
index 0cbafa9d..00000000
--- a/packages/generator-fluxible/app/templates/.eslintrc
+++ /dev/null
@@ -1,7 +0,0 @@
----
- parser: "babel-eslint"
- env:
- node: true
- rules:
- indent: [2, 4]
- quotes: [2, 'single']
diff --git a/packages/generator-fluxible/app/templates/_buildgitignore b/packages/generator-fluxible/app/templates/_buildgitignore
deleted file mode 100644
index 72e8ffc0..00000000
--- a/packages/generator-fluxible/app/templates/_buildgitignore
+++ /dev/null
@@ -1 +0,0 @@
-*
diff --git a/packages/generator-fluxible/app/templates/_gitignore b/packages/generator-fluxible/app/templates/_gitignore
index eb03e3e1..6b3405c3 100644
--- a/packages/generator-fluxible/app/templates/_gitignore
+++ b/packages/generator-fluxible/app/templates/_gitignore
@@ -1,2 +1,3 @@
+dist
node_modules
*.log
diff --git a/packages/generator-fluxible/app/templates/app.js b/packages/generator-fluxible/app/templates/app.js
index 015d8ee7..6d3c046d 100644
--- a/packages/generator-fluxible/app/templates/app.js
+++ b/packages/generator-fluxible/app/templates/app.js
@@ -5,11 +5,11 @@ import RouteStore from './stores/RouteStore';
// create new fluxible instance
const app = new Fluxible({
- component: Application
+ component: Application,
});
// register stores
app.registerStore(RouteStore);
app.registerStore(ApplicationStore);
-module.exports = app;
+export default app;
diff --git a/packages/generator-fluxible/app/templates/babel.config.js b/packages/generator-fluxible/app/templates/babel.config.js
new file mode 100644
index 00000000..5207fc11
--- /dev/null
+++ b/packages/generator-fluxible/app/templates/babel.config.js
@@ -0,0 +1,14 @@
+const isNodeTarget = (api) =>
+ api.caller((caller) => caller && caller.target === 'node');
+
+module.exports = (api) => ({
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: isNodeTarget(api) ? { node: 'current' } : 'defaults',
+ },
+ ],
+ '@babel/preset-react',
+ ],
+});
diff --git a/packages/generator-fluxible/app/templates/client.js b/packages/generator-fluxible/app/templates/client.js
index 6836bcf0..280d42be 100644
--- a/packages/generator-fluxible/app/templates/client.js
+++ b/packages/generator-fluxible/app/templates/client.js
@@ -25,9 +25,7 @@ app.rehydrate(dehydratedState, (err, context) => {
const mountNode = document.getElementById('app');
debugClient('React Rendering');
- ReactDOM.render(
- createElementWithContext(context),
- mountNode,
- () => debugClient('React Rendered')
+ ReactDOM.hydrate(createElementWithContext(context), mountNode, () =>
+ debugClient('React Rendered')
);
});
diff --git a/packages/generator-fluxible/app/templates/components/Html.js b/packages/generator-fluxible/app/templates/components/Html.js
index b37f1b13..942560b3 100644
--- a/packages/generator-fluxible/app/templates/components/Html.js
+++ b/packages/generator-fluxible/app/templates/components/Html.js
@@ -2,29 +2,33 @@ import React from 'react';
import PropTypes from 'prop-types';
import ApplicationStore from '../stores/ApplicationStore';
-function Html(props) {
- return (
-
-
-
- {props.context.getStore(ApplicationStore).getPageTitle()}
-
-
-
-
-
-
-
-
-
- );
-}
+const Html = ({ context, markup, state, clientFile }) => (
+
+
+
+ {context.getStore(ApplicationStore).getPageTitle()}
+
+
+
+
+
+
+
+
+
+);
Html.propTypes = {
clientFile: PropTypes.string,
context: PropTypes.object,
markup: PropTypes.string,
- state: PropTypes.string
+ state: PropTypes.string,
};
export default Html;
diff --git a/packages/generator-fluxible/app/templates/package.json b/packages/generator-fluxible/app/templates/package.json
index b5cb5146..a6f93a72 100644
--- a/packages/generator-fluxible/app/templates/package.json
+++ b/packages/generator-fluxible/app/templates/package.json
@@ -1,48 +1,36 @@
{
- "name": "<%= name %>",
- "version": "0.0.0",
- "private": true,
- "main": "start.js",
- "scripts": {
- "build": "webpack & webpack --config webpack.config.production.js",
- "dev": "node webpack-dev-server.js",
- "lint": "eslint ./*.js ./**/*.js",
- "start": "node start.js"
- },
- "dependencies": {
- "babel": "^6.5.2",
- "babel-core": "^6.6.4",
- "babel-preset-es2015": "^6.6.0",
- "babel-preset-react": "^6.5.0",
- "babel-register": "^6.6.0",
- "body-parser": "^1.6.4",
- "compression": "^1.5.1",
- "cookie-parser": "^1.3.3",
- "csurf": "^1.6.3",
- "debug": "^2.0.0",
- "express": "^4.3.2",
- "express-state": "^1.2.0",
- "fluxible": "^1.0.0",
- "fluxible-addons-react": "^0.2.0",
- "fluxible-plugin-fetchr": "^0.3.0",
- "fluxible-router": "^0.4.0",
- "react": "^16.0.0",
- "react-dom": "^16.0.0",
- "serialize-javascript": "^4.0.0",
- "serve-favicon": "^2.1.6"
- },
- "devDependencies": {
- "babel-eslint": "^10.0.0",
- "babel-loader": "^6.2.4",
- "bundle-loader": "^0.5.0",
- "eslint": "^6.0.0",
- "eslint-plugin-babel": "^5.0.0",
- "eslint-plugin-react": "^7.0.0",
- "json-loader": "^0.5.1",
- "nodemon": "^1.2.1",
- "react-hot-loader": "^1.2.8",
- "shelljs": "^0.6.0",
- "webpack": "^1.12.4",
- "webpack-dev-server": "^1.6.5"
- }
+ "name": "<%= name %>",
+ "version": "0.0.0",
+ "private": true,
+ "main": "dist/server.js",
+ "scripts": {
+ "build": "NODE_ENV=production webpack",
+ "dev": "npm run dev:browser & npm run dev:server",
+ "dev:browser": "NODE_ENV=development webpack --watch --no-stats",
+ "dev:server": "NODE_ENV=development nodemon",
+ "start": "node ."
+ },
+ "dependencies": {
+ "body-parser": "^1.19.0",
+ "compression": "^1.7.4",
+ "debug": "^4.3.1",
+ "express": "^4.17.1",
+ "fluxible": "^1.0.0",
+ "fluxible-addons-react": "^1.0.0-beta.1",
+ "fluxible-plugin-fetchr": "^0.3.11",
+ "fluxible-router": "^2.0.0-beta.9.0",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2",
+ "serialize-javascript": "^5.0.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.13.16",
+ "@babel/preset-env": "^7.13.15",
+ "@babel/preset-react": "^7.13.13",
+ "babel-loader": "^8.2.2",
+ "nodemon": "^2.0.7",
+ "webpack": "^5.36.1",
+ "webpack-cli": "^4.6.0",
+ "webpack-node-externals": "^3.0.0"
+ }
}
diff --git a/packages/generator-fluxible/app/templates/server.js b/packages/generator-fluxible/app/templates/server.js
index 07906e2c..415a5c9c 100644
--- a/packages/generator-fluxible/app/templates/server.js
+++ b/packages/generator-fluxible/app/templates/server.js
@@ -10,10 +10,10 @@ import compression from 'compression';
import bodyParser from 'body-parser';
import path from 'path';
import serialize from 'serialize-javascript';
-import {navigateAction} from 'fluxible-router';
+import { navigateAction } from 'fluxible-router';
import debugLib from 'debug';
import React from 'react';
-import ReactDOM from 'react-dom/server';
+import ReactDOMServer from 'react-dom/server';
import app from './app';
import HtmlComponent from './components/Html';
import { createElementWithContext } from 'fluxible-addons-react';
@@ -22,7 +22,7 @@ const env = process.env.NODE_ENV;
const debug = debugLib('<%= name %>');
const server = express();
-server.use('/public', express['static'](path.join(__dirname, '/build')));
+server.use('/public', express['static'](path.join(__dirname, 'public')));
server.use(compression());
server.use(bodyParser.json());
@@ -30,37 +30,44 @@ server.use((req, res, next) => {
const context = app.createContext();
debug('Executing navigate action');
- context.getActionContext().executeAction(navigateAction, {
- url: req.url
- }, (err) => {
- if (err) {
- if (err.statusCode && err.statusCode === 404) {
- // Pass through to next middleware
- next();
- } else {
- next(err);
+ context.getActionContext().executeAction(
+ navigateAction,
+ {
+ url: req.url,
+ },
+ (err) => {
+ if (err) {
+ if (err.statusCode && err.statusCode === 404) {
+ // Pass through to next middleware
+ next();
+ } else {
+ next(err);
+ }
+ return;
}
- return;
- }
- debug('Exposing context state');
- const exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';
+ debug('Exposing context state');
+ const exposed =
+ 'window.App=' + serialize(app.dehydrate(context)) + ';';
- debug('Rendering Application component into html');
- const markup = ReactDOM.renderToString(createElementWithContext(context));
- const htmlElement = React.createElement(HtmlComponent, {
- clientFile: env === 'production' ? 'main.min.js' : 'main.js',
- context: context.getComponentContext(),
- state: exposed,
- markup: markup
- });
- const html = ReactDOM.renderToStaticMarkup(htmlElement);
+ debug('Rendering Application component into html');
+ const markup = ReactDOMServer.renderToString(
+ createElementWithContext(context)
+ );
+ const htmlElement = React.createElement(HtmlComponent, {
+ clientFile: env === 'production' ? 'main.min.js' : 'main.js',
+ context: context.getComponentContext(),
+ state: exposed,
+ markup: markup,
+ });
+ const html = ReactDOMServer.renderToStaticMarkup(htmlElement);
- debug('Sending markup');
- res.type('html');
- res.write('' + html);
- res.end();
- });
+ debug('Sending markup');
+ res.type('html');
+ res.write('' + html);
+ res.end();
+ }
+ );
});
const port = process.env.PORT || 3000;
diff --git a/packages/generator-fluxible/app/templates/start.js b/packages/generator-fluxible/app/templates/start.js
deleted file mode 100644
index 22fa4d87..00000000
--- a/packages/generator-fluxible/app/templates/start.js
+++ /dev/null
@@ -1,3 +0,0 @@
-require('babel-register');
-
-module.exports = require('./server');
diff --git a/packages/generator-fluxible/app/templates/webpack-dev-server.js b/packages/generator-fluxible/app/templates/webpack-dev-server.js
deleted file mode 100644
index f30be00d..00000000
--- a/packages/generator-fluxible/app/templates/webpack-dev-server.js
+++ /dev/null
@@ -1,18 +0,0 @@
-var webpack = require('webpack');
-var WebpackDevServer = require('webpack-dev-server');
-var config = require('./webpack.config');
-var shell = require('shelljs');
-
-new WebpackDevServer(webpack(config), {
- publicPath: config.output.publicPath,
- hot: true,
- historyApiFallback: true,
- //quiet: true,
- proxy: {
- '*': { target: 'http://localhost:3001' }
- }
-}).listen(3000, function () {
- shell.env.PORT = shell.env.PORT || 3001;
- shell.exec('"./node_modules/.bin/nodemon" start.js -e js,jsx', function () {});
- console.log('Webpack Dev Server listening on port 3000');
-});
diff --git a/packages/generator-fluxible/app/templates/webpack.config.js b/packages/generator-fluxible/app/templates/webpack.config.js
index 3c3b0539..a85c20d7 100644
--- a/packages/generator-fluxible/app/templates/webpack.config.js
+++ b/packages/generator-fluxible/app/templates/webpack.config.js
@@ -1,46 +1,42 @@
-var webpack = require('webpack');
-var path = require('path');
+const path = require('path');
+const nodeExternals = require('webpack-node-externals');
-var webpackConfig = {
- resolve: {
- extensions: ['', '.js', '.jsx']
- },
- entry: [
- 'webpack-dev-server/client?http://localhost:3000',
- 'webpack/hot/only-dev-server',
- './client.js'
- ],
- output: {
- path: path.resolve('./build/js'),
- publicPath: '/public/js/',
- filename: 'main.js'
- },
+const isProduction = process.env.NODE_ENV !== 'development';
+
+const commonConfig = {
+ mode: isProduction ? 'production' : 'development',
module: {
- loaders: [
+ rules: [
{
- test: /\.(js|jsx)$/,
+ test: /\.m?js$/,
exclude: /node_modules/,
- loaders: [
- require.resolve('react-hot-loader'),
- require.resolve('babel-loader')
- ]
+ use: { loader: 'babel-loader' },
},
- { test: /\.json$/, loader: 'json-loader'}
- ]
+ ],
},
- node: {
- setImmediate: false
+};
+
+const browserConfig = {
+ ...commonConfig,
+ target: 'web',
+ entry: './client.js',
+ output: {
+ filename: isProduction ? 'main.min.js' : 'main.js',
+ path: path.resolve('./dist/public'),
+ publicPath: '/public/',
+ },
+};
+
+const serverConfig = {
+ ...commonConfig,
+ target: 'node',
+ entry: './server.js',
+ output: {
+ filename: 'server.js',
+ path: path.resolve(__dirname, 'dist'),
},
- plugins: [
- new webpack.HotModuleReplacementPlugin(),
- new webpack.NoErrorsPlugin(),
- new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: JSON.stringify(process.env.NODE_ENV)
- }
- })
- ],
- devtool: 'eval'
+ externals: [nodeExternals()],
+ externalsPresets: { node: true },
};
-module.exports = webpackConfig;
+module.exports = [browserConfig, serverConfig];
diff --git a/packages/generator-fluxible/app/templates/webpack.config.production.js b/packages/generator-fluxible/app/templates/webpack.config.production.js
deleted file mode 100644
index 1411cd70..00000000
--- a/packages/generator-fluxible/app/templates/webpack.config.production.js
+++ /dev/null
@@ -1,47 +0,0 @@
-var webpack = require('webpack');
-var path = require('path');
-
-var webpackConfig = {
- resolve: {
- extensions: ['', '.js']
- },
- entry: [
- './client.js'
- ],
- output: {
- path: path.resolve('./build/js'),
- publicPath: '/public/js/',
- filename: 'main.min.js'
- },
- module: {
- loaders: [
- {
- test: /\.(js|jsx)$/,
- exclude: /node_modules/,
- loaders: [
- require.resolve('babel-loader')
- ]
- },
- { test: /\.json$/, loader: 'json-loader'}
- ]
- },
- node: {
- setImmediate: false
- },
- plugins: [
- new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: JSON.stringify('production')
- }
- }),
- new webpack.optimize.DedupePlugin(),
- new webpack.optimize.UglifyJsPlugin({
- compress: {
- warnings: false
- }
- })
- ],
- devtool: 'source-map'
-};
-
-module.exports = webpackConfig;
diff --git a/packages/generator-fluxible/package.json b/packages/generator-fluxible/package.json
index 59f2e6e5..4cba3185 100644
--- a/packages/generator-fluxible/package.json
+++ b/packages/generator-fluxible/package.json
@@ -8,9 +8,6 @@
"name": "Seth Bertalotto",
"email": "sbertal@yahoo-inc.com"
},
- "engines": {
- "node": ">=0.10.0"
- },
"scripts": {
"cover": "BABEL_ENV=test ../../node_modules/.bin/nyc ../../node_modules/.bin/_mocha tests/unit --recursive --reporter spec",
"lint": "../../node_modules/.bin/eslint app/ tests/",
diff --git a/packages/generator-fluxible/tests/unit/test-app.js b/packages/generator-fluxible/tests/unit/test-app.js
index f139a24d..49d2a893 100644
--- a/packages/generator-fluxible/tests/unit/test-app.js
+++ b/packages/generator-fluxible/tests/unit/test-app.js
@@ -12,7 +12,8 @@ var os = require('os');
describe('generator-fluxible', function () {
describe('app', function () {
before(function (done) {
- helpers.run(path.join(__dirname, '../../app'))
+ helpers
+ .run(path.join(__dirname, '../../app'))
.inDir(path.join(os.tmpdir(), './temp-test'))
.withOptions({ 'skip-install': true })
.on('end', done);
@@ -21,11 +22,9 @@ describe('generator-fluxible', function () {
it('creates files', function () {
assert.file([
'package.json',
- '.editorconfig',
- '.babelrc',
- '.eslintrc',
+ 'babel.config.js',
'app.js',
- 'components/Application.js'
+ 'components/Application.js',
]);
});
});