From d86e74c046a288aa81e89238e36d96b92d22b9c7 Mon Sep 17 00:00:00 2001 From: Joel Chen Date: Thu, 24 Sep 2020 15:12:07 -0700 Subject: [PATCH] fix css modules --- .../xarc-app-dev/src/config/babel/babelrc.ts | 72 +++++--- packages/xarc-app/src/index.ts | 2 +- .../src/partials/extract-style.ts | 25 ++- .../src/util/detect-css-module.ts | 10 +- samples/hapi-app-css-modules/.browserslistrc | 4 + samples/hapi-app-css-modules/.editorconfig | 11 ++ samples/hapi-app-css-modules/.eslintrc.js | 11 ++ samples/hapi-app-css-modules/.gitattributes | 1 + samples/hapi-app-css-modules/.gitignore | 158 ++++++++++++++++++ samples/hapi-app-css-modules/.travis.yml | 5 + samples/hapi-app-css-modules/.yo-rc.json | 5 + samples/hapi-app-css-modules/LICENSE | 13 ++ samples/hapi-app-css-modules/README.md | 27 +++ .../archetype/config/index.js | 7 + samples/hapi-app-css-modules/babel.config.js | 4 + .../hapi-app-css-modules/config/default.js | 87 ++++++++++ .../config/development.json | 16 ++ .../hapi-app-css-modules/config/production.js | 23 +++ .../config/production.json | 9 + samples/hapi-app-css-modules/package.json | 86 ++++++++++ .../src/client/.babelrc.js | 3 + .../src/client/.eslintrc.js | 11 ++ .../hapi-app-css-modules/src/client/app.jsx | 43 +++++ .../src/client/components/home.jsx | 17 ++ .../src/client/components/styles.css | 3 + .../src/client/routes.jsx | 36 ++++ .../src/server/.eslintrc.js | 11 ++ .../hapi-app-css-modules/src/server/index.js | 31 ++++ .../src/server/routes/init-top.jsx | 3 + .../src/server/views/index-view.jsx | 29 ++++ .../hapi-app-css-modules/webpack.config.js | 17 ++ samples/hapi-app-css-modules/xclap.js | 51 ++++++ 32 files changed, 796 insertions(+), 35 deletions(-) create mode 100644 samples/hapi-app-css-modules/.browserslistrc create mode 100644 samples/hapi-app-css-modules/.editorconfig create mode 100644 samples/hapi-app-css-modules/.eslintrc.js create mode 100644 samples/hapi-app-css-modules/.gitattributes create mode 100644 samples/hapi-app-css-modules/.gitignore create mode 100644 samples/hapi-app-css-modules/.travis.yml create mode 100644 samples/hapi-app-css-modules/.yo-rc.json create mode 100644 samples/hapi-app-css-modules/LICENSE create mode 100644 samples/hapi-app-css-modules/README.md create mode 100644 samples/hapi-app-css-modules/archetype/config/index.js create mode 100644 samples/hapi-app-css-modules/babel.config.js create mode 100644 samples/hapi-app-css-modules/config/default.js create mode 100644 samples/hapi-app-css-modules/config/development.json create mode 100644 samples/hapi-app-css-modules/config/production.js create mode 100644 samples/hapi-app-css-modules/config/production.json create mode 100644 samples/hapi-app-css-modules/package.json create mode 100644 samples/hapi-app-css-modules/src/client/.babelrc.js create mode 100644 samples/hapi-app-css-modules/src/client/.eslintrc.js create mode 100644 samples/hapi-app-css-modules/src/client/app.jsx create mode 100644 samples/hapi-app-css-modules/src/client/components/home.jsx create mode 100644 samples/hapi-app-css-modules/src/client/components/styles.css create mode 100644 samples/hapi-app-css-modules/src/client/routes.jsx create mode 100644 samples/hapi-app-css-modules/src/server/.eslintrc.js create mode 100644 samples/hapi-app-css-modules/src/server/index.js create mode 100644 samples/hapi-app-css-modules/src/server/routes/init-top.jsx create mode 100644 samples/hapi-app-css-modules/src/server/views/index-view.jsx create mode 100644 samples/hapi-app-css-modules/webpack.config.js create mode 100644 samples/hapi-app-css-modules/xclap.js diff --git a/packages/xarc-app-dev/src/config/babel/babelrc.ts b/packages/xarc-app-dev/src/config/babel/babelrc.ts index ac16a87c9..45072a701 100644 --- a/packages/xarc-app-dev/src/config/babel/babelrc.ts +++ b/packages/xarc-app-dev/src/config/babel/babelrc.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/no-var-requires, no-console, @typescript-eslint/ban-ts-ignore */ -export {}; /* * A single babel RC for all transpiling, including client and server code. * When transpiling for node.js, env XARC_BABEL_TARGET should be set to "node" * and this file will set preset-env targets accordingly. */ +const requireAt = require("require-at"); const ck = require("chalker"); const archetype = require("@xarc/app-dev/config/archetype")(); const optionalRequire = require("optional-require")(require); @@ -48,6 +48,54 @@ const isProduction = (BABEL_ENV || NODE_ENV) === "production"; const isTest = (BABEL_ENV || NODE_ENV) === "test"; const isNodeTarget = XARC_BABEL_TARGET === "node"; +/** + * https://www.npmjs.com/package/babel-plugin-react-css-modules + * + * This plugin enhances the CSS module support from css-loader. It adds a new + * prop styleName in addition to the className prop. This also automatically + * make it work for SSR. + * + * Currently, looks like the author has been inactive on maintaining this plugin + * and there's some compatibility issue with css-loader 4.x. + * https://github.com/gajus/babel-plugin-react-css-modules/issues/291 + * + * Resolution: TBD + */ +const getReactCssModulePlugin = () => { + if (!enableCssModule) { + return null; + } + + const postCssPath = optionalRequire.resolve("@xarc/opt-postcss/package.json"); + + if (!postCssPath) { + return null; + } + + const babelReactCssModulePlugin = requireAt(postCssPath)("babel-plugin-react-css-modules"); + + return [ + [ + babelReactCssModulePlugin, + { + generateScopedName: `${isProduction ? "" : "[name]__[local]___"}[hash:base64:5]`, + filetypes: { + ".scss": { + syntax: "postcss-scss", + plugins: ["postcss-nested"] + }, + ".styl": { + syntax: "sugarss" + }, + ".less": { + syntax: "postcss-less" + } + } + } + ] + ]; +}; + const basePlugins = [ !isNodeTarget && enableDynamicImport && "@babel/plugin-syntax-dynamic-import", // add plugin for loadable component @@ -111,27 +159,7 @@ const plugins = basePlugins.concat( ], // css module support // Note: this is needed for server side (node.js) also. - enableCssModule && [ - [ - "babel-plugin-react-css-modules", - { - context: "./src", - generateScopedName: `${isProduction ? "" : "[name]__[local]___"}[hash:base64:5]`, - filetypes: { - ".scss": { - syntax: "postcss-scss", - plugins: ["postcss-nested"] - }, - ".styl": { - syntax: "sugarss" - }, - ".less": { - syntax: "postcss-less" - } - } - } - ] - ], + getReactCssModulePlugin(), !isNodeTarget && enableKarmaCov && [ getPluginFrom(["@xarc/opt-karma", "electrode-archetype-opt-karma"], "babel-plugin-istanbul") diff --git a/packages/xarc-app/src/index.ts b/packages/xarc-app/src/index.ts index 51c806fcc..07d1f32f7 100644 --- a/packages/xarc-app/src/index.ts +++ b/packages/xarc-app/src/index.ts @@ -155,7 +155,7 @@ export function load( * https://github.com/webpack/css-loader#local-scope * https://github.com/css-modules/postcss-modules-scope */ - if (options.cssModuleHook === true) { + if (options.cssModuleHook !== false) { const opts = Object.assign( { generateScopedName: "[name]__[local]___[hash:base64:5]", diff --git a/packages/xarc-webpack/src/partials/extract-style.ts b/packages/xarc-webpack/src/partials/extract-style.ts index eb4ca6ae8..077d150b2 100644 --- a/packages/xarc-webpack/src/partials/extract-style.ts +++ b/packages/xarc-webpack/src/partials/extract-style.ts @@ -1,7 +1,4 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ - -/* eslint-disable max-statements, complexity */ - +/* eslint-disable @typescript-eslint/no-var-requires, max-statements */ import * as Path from "path"; const archetypeConfig = require("@xarc/app-dev/config/archetype"); @@ -74,9 +71,9 @@ module.exports = function() { const isDevelopment = !isProduction; const archetype = archetypeConfig(); - const { hasPostCss, atImport, postcssPresetEnv, postcssLoader } = loadPostCss(); + const cssModuleSupport = detectCssModule(); - const cssModuleSupport = hasPostCss && detectCssModule(); + const { hasPostCss, atImport, postcssPresetEnv, postcssLoader } = loadPostCss(); const rules = []; @@ -140,7 +137,13 @@ module.exports = function() { use: [ { loader: MiniCssExtractPlugin.loader, - options: { hmr: isDevelopment, reload: isDevelopment, publicPath: "" } + options: { + hmr: isDevelopment, + reload: isDevelopment, + publicPath: "", + esModule: true, + modules: Boolean(cssModuleSupport) + } }, ...getCssQueryUse() ] @@ -157,7 +160,13 @@ module.exports = function() { use: [ { loader: MiniCssExtractPlugin.loader, - options: { hmr: isDevelopment, reload: isDevelopment, publicPath: "" } + options: { + hmr: isDevelopment, + reload: isDevelopment, + publicPath: "", + esModule: true, + modules: Boolean(cssModuleSupport) + } }, ...getCssQueryUse().concat({ loader: sassLoader } as any) ] diff --git a/packages/xarc-webpack/src/util/detect-css-module.ts b/packages/xarc-webpack/src/util/detect-css-module.ts index 924804b4b..7d8ec7afe 100644 --- a/packages/xarc-webpack/src/util/detect-css-module.ts +++ b/packages/xarc-webpack/src/util/detect-css-module.ts @@ -8,14 +8,16 @@ const AppMode = archetype.AppMode; const getOptRequire = require("../util/get-opt-require"); function detectCSSModule() { - if (getOptRequire(["@xarc/opt-postcss", "electrode-archetype-opt-postcss"]).invalid) { - return false; - } - + // if user explicitly says they want CSS module support, then we enable it if (archetype.webpack.cssModuleSupport !== undefined) { return Boolean(archetype.webpack.cssModuleSupport); } + // without postcss we don't want to do CSS module by default + if (getOptRequire(["@xarc/opt-postcss", "electrode-archetype-opt-postcss"]).invalid) { + return false; + } + const scanned = filterScanDir.sync({ dir: Path.resolve(AppMode.src.client), grouping: true, diff --git a/samples/hapi-app-css-modules/.browserslistrc b/samples/hapi-app-css-modules/.browserslistrc new file mode 100644 index 000000000..d66332951 --- /dev/null +++ b/samples/hapi-app-css-modules/.browserslistrc @@ -0,0 +1,4 @@ +# Browsers that we support +last 2 versions +ie >= 11 +> 5% diff --git a/samples/hapi-app-css-modules/.editorconfig b/samples/hapi-app-css-modules/.editorconfig new file mode 100644 index 000000000..beffa3084 --- /dev/null +++ b/samples/hapi-app-css-modules/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/samples/hapi-app-css-modules/.eslintrc.js b/samples/hapi-app-css-modules/.eslintrc.js new file mode 100644 index 000000000..2f1a6a306 --- /dev/null +++ b/samples/hapi-app-css-modules/.eslintrc.js @@ -0,0 +1,11 @@ +var path = require("path"); +var archetype = require("@xarc/app/config/archetype")(); +var archetypeEslint = path.join(archetype.config.eslint, ".eslintrc-react"); + +function dotify(p) { + return path.isAbsolute(p) ? p : "." + path.sep + p; +} + +module.exports = { + extends: dotify(path.relative(__dirname, archetypeEslint)) +}; diff --git a/samples/hapi-app-css-modules/.gitattributes b/samples/hapi-app-css-modules/.gitattributes new file mode 100644 index 000000000..176a458f9 --- /dev/null +++ b/samples/hapi-app-css-modules/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/samples/hapi-app-css-modules/.gitignore b/samples/hapi-app-css-modules/.gitignore new file mode 100644 index 000000000..91416c552 --- /dev/null +++ b/samples/hapi-app-css-modules/.gitignore @@ -0,0 +1,158 @@ + + +# Created by https://www.gitignore.io/api/gitbook,node,webstorm,bower,osx + +### GitBook ### +# Node rules: +## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +## Dependency directory +## Commenting this out is preferred by some people, see +## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git +node_modules + +# Book build output +_book + +# eBook build output +*.epub +*.mobi +*.pdf + + +### Node ### +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git +node_modules + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + + +### WebStorm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries +# .idea/shelf + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + + +### Bower ### +bower_components +.bower-cache +.bower-registry +.bower-tmp + + +### OSX ### +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# others +.hg +.project +.tmp + +# Build +dist +Procfile +config/assets.json +npm-shrinkwrap.json + +.isomorphic-loader-config.json + diff --git a/samples/hapi-app-css-modules/.travis.yml b/samples/hapi-app-css-modules/.travis.yml new file mode 100644 index 000000000..6e684fc58 --- /dev/null +++ b/samples/hapi-app-css-modules/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 7 + - 6 + - 4 diff --git a/samples/hapi-app-css-modules/.yo-rc.json b/samples/hapi-app-css-modules/.yo-rc.json new file mode 100644 index 000000000..0b4b07821 --- /dev/null +++ b/samples/hapi-app-css-modules/.yo-rc.json @@ -0,0 +1,5 @@ +{ + "generator-electrode": { + "serverType": "HapiJS" + } +} \ No newline at end of file diff --git a/samples/hapi-app-css-modules/LICENSE b/samples/hapi-app-css-modules/LICENSE new file mode 100644 index 000000000..1204d8f56 --- /dev/null +++ b/samples/hapi-app-css-modules/LICENSE @@ -0,0 +1,13 @@ +Copyright 2019 hapi-app + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/samples/hapi-app-css-modules/README.md b/samples/hapi-app-css-modules/README.md new file mode 100644 index 000000000..abdf9d9ae --- /dev/null +++ b/samples/hapi-app-css-modules/README.md @@ -0,0 +1,27 @@ +# hapi-app [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] +> test test + +## Installation + +```sh +$ npm install --save hapi-app +``` + +## Usage + +```js +var hapiApp = require('hapi-app'); + +hapiApp('Rainbow'); +``` +## License + +Apache-2.0 © [John Smith](http://www.test.com) + + +[npm-image]: https://badge.fury.io/js/hapi-app.svg +[npm-url]: https://npmjs.org/package/hapi-app +[travis-image]: https://travis-ci.org/test/hapi-app.svg?branch=master +[travis-url]: https://travis-ci.org/test/hapi-app +[daviddm-image]: https://david-dm.org/test/hapi-app.svg?theme=shields.io +[daviddm-url]: https://david-dm.org/test/hapi-app diff --git a/samples/hapi-app-css-modules/archetype/config/index.js b/samples/hapi-app-css-modules/archetype/config/index.js new file mode 100644 index 000000000..9ec285b8e --- /dev/null +++ b/samples/hapi-app-css-modules/archetype/config/index.js @@ -0,0 +1,7 @@ +module.exports = { + options: {}, + babel: {}, + webpack: { + cssModuleSupport: true + } +}; diff --git a/samples/hapi-app-css-modules/babel.config.js b/samples/hapi-app-css-modules/babel.config.js new file mode 100644 index 000000000..fb1d6601e --- /dev/null +++ b/samples/hapi-app-css-modules/babel.config.js @@ -0,0 +1,4 @@ +"use strict"; +module.exports = { + extends: "@xarc/app-dev/config/babel/babelrc.js" +}; diff --git a/samples/hapi-app-css-modules/config/default.js b/samples/hapi-app-css-modules/config/default.js new file mode 100644 index 000000000..6814df086 --- /dev/null +++ b/samples/hapi-app-css-modules/config/default.js @@ -0,0 +1,87 @@ +"use strict"; + +const defaultListenPort = 3000; + +const portFromEnv = () => { + const x = parseInt(process.env.APP_SERVER_PORT || process.env.PORT, 10); + /* istanbul ignore next */ + return x !== null && !isNaN(x) ? x : defaultListenPort; +}; + +module.exports = { + ui: { + demo: "hello from hapi sample ui config", + webappPrefix: "hapiSample" + }, + plugins: { + good: { + module: "@hapi/good", + options: { + reporters: { + myConsoleReporter: [ + { + module: "@hapi/good-console" + }, + "stdout" + ] + } + } + }, + "webpack-dev": { + module: "@xarc/app-dev/lib/webpack-dev-hapi", + enable: process.env.WEBPACK_DEV === "true", + options: { + // webpack dev middleware options + dev: { + // user reporter that's called by the archetype's reporter + reporter: reporterOptions => { + // For example, you can start app server with `clap devbrk` and attach + // to it with chrome://inspect, and then enable this debugger statement + // so chrome stop here every time webpack middleware finish compiling + // debugger + } + } + } + }, + "electrode-ui-config/hapi-plugin": {}, + inert: { + module: "@hapi/inert", + enable: true + }, + electrodeStaticPaths: { + enable: true, + options: { + pathPrefix: "dist" + } + }, // + webapp: { + module: "electrode-react-webapp/lib/hapi", + options: { + pageTitle: "hapi-app", + insertTokenIds: false, + paths: { + "/{args*}": { + content: { + module: "./{{env.APP_SRC_DIR}}/server/views/index-view" + } + } + } + } + }, // + "electrode-cookies/hapi-plugin": {} + // + }, + connections: { + default: { + host: process.env.HOST, + address: process.env.HOST_IP || "0.0.0.0", + port: portFromEnv(), + routes: { + cors: false + }, + state: { + ignoreErrors: true + } + } + } +}; diff --git a/samples/hapi-app-css-modules/config/development.json b/samples/hapi-app-css-modules/config/development.json new file mode 100644 index 000000000..16195bb14 --- /dev/null +++ b/samples/hapi-app-css-modules/config/development.json @@ -0,0 +1,16 @@ +{ + "connections": { + "default": { + "routes": { + "cors": true + } + } + }, + "plugins": { + "webapp": { + "options": { + "insertTokenIds": true + } + } + } +} diff --git a/samples/hapi-app-css-modules/config/production.js b/samples/hapi-app-css-modules/config/production.js new file mode 100644 index 000000000..668d4ad20 --- /dev/null +++ b/samples/hapi-app-css-modules/config/production.js @@ -0,0 +1,23 @@ +// +// This file is here to allow enabling the plugins inert and electrodeStaticPaths, overriding the +// settings in production.json, in order to serve the static JS and CSS bundle files from +// the dist directory so you can test your app server locally in production mode. +// +// When running in a real production environment where your static files are most likely served +// by a dedicated CDN server, you might want to turn these plugins off. +// + +const serveStaticFiles = () => { + return process.env.STATIC_FILES_OFF !== "true"; +}; + +module.exports = { + "plugins": { + "inert": { + "enable": serveStaticFiles() + }, + "electrodeStaticPaths": { + "enable": serveStaticFiles() + } + } +}; diff --git a/samples/hapi-app-css-modules/config/production.json b/samples/hapi-app-css-modules/config/production.json new file mode 100644 index 000000000..7e70a0e3b --- /dev/null +++ b/samples/hapi-app-css-modules/config/production.json @@ -0,0 +1,9 @@ +{ + "connections": { + "default": { + "routes": { + "cors": false + } + } + } +} diff --git a/samples/hapi-app-css-modules/package.json b/samples/hapi-app-css-modules/package.json new file mode 100644 index 000000000..34aa401ce --- /dev/null +++ b/samples/hapi-app-css-modules/package.json @@ -0,0 +1,86 @@ +{ + "name": "hapi-app", + "version": "0.0.1", + "description": "test test", + "homepage": "http://test", + "author": { + "name": "John Smith", + "email": "john@smith.com", + "url": "http://www.test.com" + }, + "contributors": [], + "files": [ + "server", + "src", + "lib", + "dist" + ], + "main": "lib/server/index.js", + "keywords": [ + "test", + "electrode" + ], + "repository": { + "type": "git", + "url": "https://github.com/1846689910/electrode.git" + }, + "license": "Apache-2.0", + "engines": { + "node": ">= 8", + "npm": ">= 5" + }, + "scripts": { + "dev": "clap -q dev", + "build": "clap build", + "prod-start": "NODE_ENV=production clap -n -x electrode/build prod", + "start": "if test \"$NODE_ENV\" = \"production\"; then npm run prod-start; else clap dev; fi", + "test": "clap check", + "coverage": "clap check", + "prod": "echo 'Starting standalone server in PROD mode'; NODE_ENV=production node ./lib/server/" + }, + "dependencies": { + "@hapi/good": "^8.2.4", + "@hapi/good-console": "^8.1.2", + "@hapi/inert": "^5.1.2", + "@xarc/app": "^8.0.0", + "@xarc/opt-react": "^1.0.0", + "electrode-confippet": "^1.5.0", + "electrode-cookies": "^1.0.0", + "electrode-react-webapp": "^3.2.0", + "electrode-redux-router-engine": "^2.1.8", + "electrode-server": "^3.0.0", + "electrode-static-paths": "^3.0.0", + "electrode-ui-config": "^1.1.2", + "lodash": "^4.17.11", + "milligram": "^1.3.0", + "react-notify-toast": "^0.5.0", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.1.2" + }, + "devDependencies": { + "@xarc/app-dev": "^8.0.0", + "@xarc/opt-jest": "^1.0.0", + "@xarc/opt-less": "../../packages/xarc-opt-less", + "@xarc/opt-postcss": "^1.0.0", + "@xarc/opt-sass": "../../packages/xarc-opt-sass", + "@xarc/opt-stylus": "../../packages/xarc-opt-stylus", + "webpack-hook-plugin": "^1.0.7" + }, + "fyn": { + "dependencies": { + "@xarc/app": "../../packages/xarc-app", + "@xarc/opt-react": "../../packages/xarc-opt-react", + "electrode-cookies": "../../packages/electrode-cookies", + "electrode-react-webapp": "../../packages/electrode-react-webapp", + "electrode-redux-router-engine": "../../packages/electrode-redux-router-engine", + "electrode-ui-config": "../../packages/electrode-ui-config" + }, + "devDependencies": { + "@xarc/app-dev": "../../packages/xarc-app-dev", + "@xarc/opt-jest": "../../packages/xarc-opt-jest", + "@xarc/opt-postcss": "../../packages/xarc-opt-postcss", + "@xarc/opt-stylus": "../../packages/xarc-opt-stylus" + } + }, + "optionalDependencies": {} +} diff --git a/samples/hapi-app-css-modules/src/client/.babelrc.js b/samples/hapi-app-css-modules/src/client/.babelrc.js new file mode 100644 index 000000000..8d166bca2 --- /dev/null +++ b/samples/hapi-app-css-modules/src/client/.babelrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: "@xarc/app-dev/config/babel/babelrc-client.js" +}; diff --git a/samples/hapi-app-css-modules/src/client/.eslintrc.js b/samples/hapi-app-css-modules/src/client/.eslintrc.js new file mode 100644 index 000000000..2f1a6a306 --- /dev/null +++ b/samples/hapi-app-css-modules/src/client/.eslintrc.js @@ -0,0 +1,11 @@ +var path = require("path"); +var archetype = require("@xarc/app/config/archetype")(); +var archetypeEslint = path.join(archetype.config.eslint, ".eslintrc-react"); + +function dotify(p) { + return path.isAbsolute(p) ? p : "." + path.sep + p; +} + +module.exports = { + extends: dotify(path.relative(__dirname, archetypeEslint)) +}; diff --git a/samples/hapi-app-css-modules/src/client/app.jsx b/samples/hapi-app-css-modules/src/client/app.jsx new file mode 100644 index 000000000..291240024 --- /dev/null +++ b/samples/hapi-app-css-modules/src/client/app.jsx @@ -0,0 +1,43 @@ +// +// This is the client side entry point for the React app. +// + +import React from "react"; +import { render, hydrate } from "react-dom"; +import { routes } from "./routes"; +import { BrowserRouter } from "react-router-dom"; +import { renderRoutes } from "react-router-config"; +import uiConfig from "electrode-ui-config"; + +// +// Add the client app start up code to a function as window.webappStart. +// The webapp's full HTML will check and call it once the js-content +// DOM is created. +// + +const start = App => { + const jsContent = document.querySelector(".js-content"); + const reactStart = render; + + reactStart( + + + , + jsContent + ); +}; + +window.hapiSampleWebappStart = () => { + uiConfig.reload(window.hapiSample_config || {}); + return start(() => renderRoutes(routes)); +}; + +// +// Hot Module Reload setup +// +if (module.hot) { + module.hot.accept("./routes", () => { + const r = require("./routes"); + start(() => renderRoutes(r.routes)); + }); +} diff --git a/samples/hapi-app-css-modules/src/client/components/home.jsx b/samples/hapi-app-css-modules/src/client/components/home.jsx new file mode 100644 index 000000000..8299861d2 --- /dev/null +++ b/samples/hapi-app-css-modules/src/client/components/home.jsx @@ -0,0 +1,17 @@ +/* + */ + +import React from "react"; +import styles from "./styles.css"; + +class Home extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
Hello World!
; + } +} + +export default Home; diff --git a/samples/hapi-app-css-modules/src/client/components/styles.css b/samples/hapi-app-css-modules/src/client/components/styles.css new file mode 100644 index 000000000..7f34cd3b1 --- /dev/null +++ b/samples/hapi-app-css-modules/src/client/components/styles.css @@ -0,0 +1,3 @@ +.wrapper { + font-size: 5em; +} diff --git a/samples/hapi-app-css-modules/src/client/routes.jsx b/samples/hapi-app-css-modules/src/client/routes.jsx new file mode 100644 index 000000000..4174361cd --- /dev/null +++ b/samples/hapi-app-css-modules/src/client/routes.jsx @@ -0,0 +1,36 @@ +import React from "react"; +import PropTypes from "prop-types"; +import Home from "./components/home"; +import { withRouter } from "react-router-dom"; +import { renderRoutes } from "react-router-config"; + +const Root = ({ route, children }) => { + return ( +
+ {renderRoutes(route.routes)} + {children} +
+ ); +}; + +Root.propTypes = { + route: PropTypes.object, + children: PropTypes.object +}; + +const routes = [ + { + path: "/", + component: withRouter(Root), + init: "./init-top", + routes: [ + { + path: "/", + exact: true, + component: Home + } + ] + } +]; + +export { routes }; diff --git a/samples/hapi-app-css-modules/src/server/.eslintrc.js b/samples/hapi-app-css-modules/src/server/.eslintrc.js new file mode 100644 index 000000000..8279510de --- /dev/null +++ b/samples/hapi-app-css-modules/src/server/.eslintrc.js @@ -0,0 +1,11 @@ +var path = require("path"); +var archetype = require("@xarc/app/config/archetype")(); +var archetypeEslint = path.join(archetype.config.eslint, ".eslintrc-node"); + +function dotify(p) { + return path.isAbsolute(p) ? p : "." + path.sep + p; +} + +module.exports = { + extends: dotify(path.relative(__dirname, archetypeEslint)) +}; diff --git a/samples/hapi-app-css-modules/src/server/index.js b/samples/hapi-app-css-modules/src/server/index.js new file mode 100644 index 000000000..594e43b66 --- /dev/null +++ b/samples/hapi-app-css-modules/src/server/index.js @@ -0,0 +1,31 @@ +"use strict"; + +/* eslint-disable global-require */ + +process.on("SIGINT", () => { + process.exit(0); +}); + +const electrodeConfippet = require("electrode-confippet"); +const support = require("@xarc/app/support"); + +// +const staticPathsDecor = require("electrode-static-paths"); +const electrodeServer = require("electrode-server"); + +const startServer = config => { + // + const decor = staticPathsDecor(); + return electrodeServer(config, [decor]); + // +}; + +module.exports = () => + support.load().then(() => { + const config = electrodeConfippet.config; + return startServer(config); + }); + +if (require.main === module) { + module.exports(); +} diff --git a/samples/hapi-app-css-modules/src/server/routes/init-top.jsx b/samples/hapi-app-css-modules/src/server/routes/init-top.jsx new file mode 100644 index 000000000..3ae05a913 --- /dev/null +++ b/samples/hapi-app-css-modules/src/server/routes/init-top.jsx @@ -0,0 +1,3 @@ +export default function initTop(a, b, c) { + return {}; +} diff --git a/samples/hapi-app-css-modules/src/server/views/index-view.jsx b/samples/hapi-app-css-modules/src/server/views/index-view.jsx new file mode 100644 index 000000000..364a0753d --- /dev/null +++ b/samples/hapi-app-css-modules/src/server/views/index-view.jsx @@ -0,0 +1,29 @@ +// +// This is the server side entry point for the React app. +// + +import ReduxRouterEngine from "electrode-redux-router-engine"; +import { routes } from "../../client/routes"; + +// +// This function is exported as the content for the webapp plugin. +// +// See config/default.json under plugins.webapp on specifying the content. +// +// When the Web server hits the routes handler installed by the webapp plugin, it +// will call this function to retrieve the content for SSR if it's enabled. +// +// + +let routesEngine; + +module.exports = async req => { + if (!routesEngine) { + routesEngine = new ReduxRouterEngine({ + routes, + webappPrefix: req.server.app.config.ui.webappPrefix + }); + } + + return routesEngine.render(req); +}; diff --git a/samples/hapi-app-css-modules/webpack.config.js b/samples/hapi-app-css-modules/webpack.config.js new file mode 100644 index 000000000..b754325ec --- /dev/null +++ b/samples/hapi-app-css-modules/webpack.config.js @@ -0,0 +1,17 @@ +// Custom Webpack Config that takes control and overrides Archetype +const { compose, env, options } = require("@xarc/app-dev/config/webpack"); +const WebpackHookPlugin = require("webpack-hook-plugin"); + +// An example to add a plugin +const wConfig = compose(options); + +if (env === "development") { + const webpackHook = new WebpackHookPlugin({ + onBuildStart: ['echo "Webpack Build starts"'], + onBuildEnd: ['echo "Webpack Build ends"'] + }); + + wConfig.plugins.push(webpackHook); +} + +module.exports = wConfig; diff --git a/samples/hapi-app-css-modules/xclap.js b/samples/hapi-app-css-modules/xclap.js new file mode 100644 index 000000000..b58906415 --- /dev/null +++ b/samples/hapi-app-css-modules/xclap.js @@ -0,0 +1,51 @@ +/* + * Tell Electrode app archetype that you want to use ES6 syntax in your server code + */ + +process.env.SERVER_ES6 = true; + +// Run app server at port 3100 to enable dev proxy at port 3000 +process.env.APP_SERVER_PORT = 3100; + +/* + * Tell Electrode app archetype that you want to use webpack dev as a middleware + * This will run webpack dev server as part of your app server. + */ + +process.env.WEBPACK_DEV_MIDDLEWARE = true; + +process.env.USE_APP_WEBPACK_CONFIG = true; + +/* + * Tell Electrode app archetype that you want to shorten css names under production env + */ + +process.env.ENABLE_SHORTEN_CSS_NAMES = true; + +/* + * Enable webpack's NodeSourcePlugin to simulate NodeJS libs in browser + * + * This basically adds a bunch of extra JavaScript to the browser to simulate + * some NodeJS modules like `process`, `console`, `Buffer`, and `global`. + * + * Docs here: + * https://github.com/webpack/docs/wiki/internal-webpack-plugins#nodenodesourcepluginoptions + * + * Note that the extra JavaScript could be substantial and adds more than 100K + * of minified JS to your browser bundle. + * + * But if you see Errors like "Uncaught ReferenceError: global is not defined", then + * the quick fix is to uncomment the line below. + */ + +// process.env.ENABLE_NODESOURCE_PLUGIN = true; + +/* + * Use PhantomJS to run your Karma Unit tests. Default is "chrome" (Chrome Headless) + */ + +// process.env.KARMA_BROWSER = "phantomjs"; + +require("@xarc/app")(); + +//