Skip to content

Commit

Permalink
convert xarc-app to ts (#1708)
Browse files Browse the repository at this point in the history
  • Loading branch information
jchip authored Jul 23, 2020
1 parent ffedf19 commit a847cd5
Show file tree
Hide file tree
Showing 7 changed files with 310 additions and 165 deletions.
21 changes: 20 additions & 1 deletion packages/xarc-app/lib/app-mode.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
"use strict";

/* eslint-disable no-param-reassign */

const Path = require("path");
const Fs = require("fs");
const subappUtil = require("subapp-util");
const logger = require("./logger");
const constants = require("./constants");

function makeAppMode(prodDir, reactLib) {
/**
* Figure out the mode app is setup.
*
* 1. src/client, src/server => lib
* 2. src/{subapp-directories}, src/server => lib
* 3. which react lib is being used (default react)
*
* And then setup the env APP_SRC_DIR so in dev mode code in src is executed
* with run time compiler like @babel/register, but in prod mode transpiled
* code in lib will be executed.
*
* @param {*} prodDir - directory to save data of the app mode
* @param {*} reactLib - UI framework (react)
*
* @returns app mode data
*/
function makeAppMode(prodDir = constants.PROD_DIR, reactLib = "react") {
const client = "client";
const server = "server";

Expand Down
69 changes: 56 additions & 13 deletions packages/xarc-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,66 @@
},
"license": "Apache-2.0",
"scripts": {
"build": "tsc",
"test": "clap check",
"format": "prettier --write --print-width 100 *.{js,jsx} `find . -type d -d 1 -exec echo '{}/**/*.{js,jsx}' \\; | egrep -v '(/node_modules/|/dist/|/coverage/)'`"
"format": "prettier --write --print-width 100 *.{js,jsx} `find . -type d -d 1 -exec echo '{}/**/*.{js,jsx}' \\; | egrep -v '(/node_modules/|/dist/|/coverage/)'`",
"prepublishOnly": "clap -n build docs && clap check",
"docs": "clap xarc/docs"
},
"files": [
"arch-clap.js",
"config",
"dist",
"lib",
"support",
"arch-clap.js",
"require.js",
"typedef.js",
"supports.js"
"support",
"supports.js",
"typedef.js"
],
"author": "Electrode (http://www.electrode.io/)",
"contributors": [
"Joel Chen <[email protected]>"
],
"dependencies": {
"@babel/runtime": "^7.8.3",
"@xarc/module-dev": "^2.1.2",
"css-modules-require-hook": "^4.0.2",
"ignore-styles": "^5.0.1",
"isomorphic-loader": "^3.1.0",
"optional-require": "^1.0.0",
"subapp-util": "^1.1.0"
},
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@types/chai": "^4.2.11",
"@types/mocha": "^7.0.2",
"@types/node": "^13.7.6",
"@types/sinon": "^9.0.0",
"@types/sinon-chai": "^3.2.4",
"@typescript-eslint/eslint-plugin": "^2.21.0",
"@typescript-eslint/parser": "^2.21.0",
"babel-eslint": "^10.1.0",
"chai": "^4.2.0",
"chalk": "^1.1.3",
"electrode-archetype-njs-module-dev": "^3.0.0",
"eslint": "^6.8.0",
"eslint-config-walmart": "^2.2.1",
"eslint-plugin-filenames": "^1.1.0",
"eslint-plugin-jsdoc": "^21.0.0",
"mocha": "^7.1.0",
"mock-require": "^3.0.3",
"nyc": "^15.0.0",
"prettier": "^1.14.2",
"prompts": "^2.2.1",
"request": "^2.88.0",
"winston": "^2.3.1"
"sinon": "^7.2.6",
"sinon-chai": "^3.3.0",
"source-map-support": "^0.5.16",
"ts-node": "^8.6.2",
"typedoc": "^0.17.4",
"typescript": "^3.8.3"
},
"engines": {
"node": ">= 6",
"npm": ">= 3"
"node": ">= 10",
"npm": ">= 6"
},
"nyc": {
"all": true,
Expand All @@ -58,12 +82,23 @@
"text-summary"
],
"exclude": [
"coverage",
"*clap.js",
"gulpfile.js",
"*clap.ts",
"coverage",
"dist",
"docs",
"gulpfile.js",
"test"
]
],
"extends": [
"@istanbuljs/nyc-config-typescript"
],
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100,
"cache": false
},
"fyn": {
"dependencies": {
Expand All @@ -78,5 +113,13 @@
"printWidth": 100,
"trailingComma": "none",
"arrowParens": "avoid"
},
"mocha": {
"require": [
"ts-node/register",
"source-map-support/register",
"./config/test/setup.js"
],
"recursive": true
}
}
207 changes: 207 additions & 0 deletions packages/xarc-app/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/* eslint-disable @typescript-eslint/no-var-requires, global-require, no-param-reassign */
/* eslint-disable no-process-exit, no-console, max-statements */
/* eslint max-statements: 0 complexity: 0 */

const optionalRequire = require("optional-require")(require);
const isoExtRequire = require("isomorphic-loader/lib/extend-require");
const makeAppMode = require("../lib/app-mode");
const Path = require("path");
const constants = require("../lib/constants");
const logger = require("../lib/logger");

let AppMode;

function getAppMode() {
if (AppMode) {
return AppMode;
}

try {
const archetype = require("@xarc/app-dev/config/archetype")();
return (AppMode = archetype.AppMode);
} catch (e) {
return (AppMode = makeAppMode(constants.PROD_DIR));
}
}

/**
* Load CSS module run time hook
*
* @param options - options for the hook
*/
export function cssModuleHook(
options: {
/**
* template for scope name to generate, default: "[hash:base64]"
*/
generateScopedName?: string;
/**
* rootDir - src or lib in production
*/
rootDir?: string;
/**
* any other options for css-modules-require-hook
*/
[key: string]: any;
} = {}
) {
const defaultRootDirPath = process.env.NODE_ENV === "production" ? "lib" : "src";
options.generateScopedName = options.generateScopedName || "[hash:base64]";
options.rootDir = options.rootDir || Path.resolve(defaultRootDirPath);

require("css-modules-require-hook")(options);
}

/**
* Load the require hook to support isomorphic assets when doing SSR
*/
export function isomorphicExtendRequire() {
return isoExtRequire({
processAssets: (assets: any) => {
const appSrcDir = (getAppMode().getEnv() || getAppMode().lib.dir).split("/")[0];
if (appSrcDir !== getAppMode().src.dir && assets.marked) {
const marked = assets.marked;
Object.keys(marked).forEach(k => {
if (k.startsWith(getAppMode().src.client) || k.startsWith(getAppMode().src.server)) {
const nk = k.replace(getAppMode().src.dir, appSrcDir);
marked[nk] = marked[k];
}
});
}

return assets;
}
}).catch((err: Error) => {
isoExtRequire._instance.interceptLoad();
});
}

/**
* Load run time supports
*
* @param options - options on what to load
* @param callback - callback after loaded (returns Promise if no callback)
* @returns nothing
*/
export function load(
/**
* support load options or a callback for when support load is done
*/
options:
| {
/**
* - boolean: true to load @babel/register
* - Object: options to be passed to @babel/register
*/
babelRegister?: any;
/**
* if true, then load and setup CSS module runtime for node.js
*/
cssModuleHook?: boolean;
/**
* if no CSS module hook, then a default ignore hook is load to avoid errors
* when trying to load CSS modules.
*
* Set this to false to avoid loading the ignore hook.
*/
ignoreStyles?: boolean;
/**
* Set to false to avoid loading node.js require hook to handle isomorphic assets
*/
isomorphicExtendRequire?: boolean;
}
| Function,
callback?: Function
) {
if (typeof options === "function") {
callback = options;
options = {};
} else {
options = options || {};
}

if (options.babelRegister) {
const babelRegister = optionalRequire("@babel/register");
if (!babelRegister) {
console.log(
"To use @babel/register mode, you need to install the @babel/register and support modules."
);
console.log("Please see documentation for more details.");
return process.exit(1);
}
const regOptions = Object.assign(
{
extensions: [".es6", ".es", ".jsx", ".js"]
},
options.babelRegister || {}
);

logger.info(
`Loading @babel/register for runtime transpilation files (extensions: ${regOptions.extensions}).`
);
logger.info(`The transpilation only occurs the first time you load a file.`);
babelRegister(regOptions);
}

/**
* css-modules-require-hook: handle css-modules on node.js server.
* similar to Babel's babel/register it compiles CSS modules in runtime.
*
* generateScopedName - Short alias for the postcss-modules-scope plugin's option.
* Helps you to specify the custom way to build generic names for the class selectors.
* You may also use a string pattern similar to the webpack's css-loader.
*
* https://github.com/css-modules/css-modules-require-hook#generatescopedname-function
* https://github.com/webpack/css-loader#local-scope
* https://github.com/css-modules/postcss-modules-scope
*/
if (options.cssModuleHook === true) {
const opts = Object.assign(
{
generateScopedName: "[name]__[local]___[hash:base64:5]",
extensions: [".scss", ".styl", ".less", ".css"],
preprocessCss: function(css, filename) {
if (filename.endsWith(".styl")) {
return require("stylus")(css)
.set("filename", filename)
.render();
} else if (filename.endsWith(".scss")) {
return require("node-sass").renderSync({
css,
file: filename
}).css;
} else {
return css;
}
},
processorOpts: { parser: require("postcss-less").parse }
},
options.cssModuleHook || {}
);

cssModuleHook(opts);
} else if (options.ignoreStyles !== false) {
optionalRequire("ignore-styles");
}

if (options.isomorphicExtendRequire !== false) {
return isomorphicExtendRequire();
}

return callback ? callback() : Promise.resolve();
}

if (!getAppMode().hasEnv()) {
const guessAppSrcDir = () => {
if (module.parent && module.parent.filename) {
const fn = module.parent.filename;
const dir = fn.substr(process.cwd().length + 1).split("/")[0];
if (dir === getAppMode().src.dir || dir === getAppMode().lib.dir) {
return `${dir}/`;
}
}
return "lib/";
};
getAppMode().setEnv(guessAppSrcDir());
}
logger.info(`${getAppMode().envKey} set to`, getAppMode().getEnv());
Loading

0 comments on commit a847cd5

Please sign in to comment.