Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: a single babel.config.js over .babelrc.js #1583

Merged
merged 3 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/xarc-app-dev/config/babel/babelrc-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module.exports = {
[
"@babel/preset-env",
{
targets: { node }
targets: node
}
],
enableTypeScript && "@babel/preset-typescript",
Expand Down
173 changes: 173 additions & 0 deletions packages/xarc-app-dev/config/babel/babelrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
"use strict";

/*
* 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 ck = require("chalker");
const requireAt = require("require-at");
const archetype = require("@xarc/app/config/archetype");
const optionalRequire = require("optional-require")(require);
const optFlow = optionalRequire("electrode-archetype-opt-flow");

const {
enableTypeScript,
flowRequireDirective,
enableFlow,
proposalDecorators,
legacyDecorators,
transformClassProps,
looseClassProps,
enableDynamicImport
} = archetype.babel;

const addFlowPlugin = Boolean(enableFlow && optFlow);
//
// Resolve full path of a plugin that's the dependency of host npm package
//
function getPluginFrom(host, pluginName) {
return requireAt(require.resolve(`${host}/package.json`)).resolve(pluginName);
}

const fileId = "xarc-app-dev:babelrc.js";

const checkEnv = names => {
names = names.filter(x => !process.env.hasOwnProperty(x));
if (names.length > 0) {
console.error(
ck`\n<red>Notice:</> ${fileId}: env ${names.join(", ")} not defined - default to 'false'\n`
);
}
};

checkEnv(["ENABLE_CSS_MODULE", "ENABLE_KARMA_COV"]);

const { BABEL_ENV, NODE_ENV, XARC_BABEL_TARGET, ENABLE_CSS_MODULE, ENABLE_KARMA_COV } = process.env;

const enableCssModule = ENABLE_CSS_MODULE === "true";
const enableKarmaCov = ENABLE_KARMA_COV === "true";
const isProduction = (BABEL_ENV || NODE_ENV) === "production";
const isTest = (BABEL_ENV || NODE_ENV) === "test";
const isNodeTarget = XARC_BABEL_TARGET === "node";

const basePlugins = [
...(!isNodeTarget && enableDynamicImport
? ["@babel/plugin-syntax-dynamic-import", "@loadable/babel-plugin"]
: [false]),
// allow decorators on class and method
// Note: This must go before @babel/plugin-proposal-class-properties
(enableTypeScript || proposalDecorators) && [
"@babel/plugin-proposal-decorators",
{ legacy: legacyDecorators }
],
//
// allow class properties. loose option compile to assignment expression instead
// of Object.defineProperty.
// Note: This must go before @babel/plugin-transform-classes
//
(enableTypeScript || transformClassProps) && [
"@babel/plugin-proposal-class-properties",
{ loose: looseClassProps }
],
//
// i18n has not been used at all and these are very outdated
// remove them for now until they can be updated
//
// [
// "babel-plugin-i18n-id-hashing",
// {
// varsContainingMessages: ["defaultMessages", "translations"]
// }
// ],
// [
// "babel-plugin-react-intl",
// {
// messagesDir: "./tmp/messages/",
// enforceDescriptions: true
// }
// ],
!isNodeTarget && "transform-node-env-inline",
!isNodeTarget && "babel-plugin-lodash",
!isNodeTarget && "@babel/plugin-transform-runtime",
addFlowPlugin && [
"@babel/plugin-transform-flow-strip-types",
{ requireDirective: flowRequireDirective }
]
];

const plugins = basePlugins.concat(
// test env
isTest && ["babel-plugin-dynamic-import-node"],
// production env
!isNodeTarget &&
isProduction && [
"@babel/plugin-transform-react-constant-elements",
[
"babel-plugin-transform-react-remove-prop-types",
{
removeImport: true
}
]
],
// css module support
!isNodeTarget &&
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"
}
}
}
]
],
!isNodeTarget &&
enableKarmaCov && [getPluginFrom("electrode-archetype-opt-karma", "babel-plugin-istanbul")]
);

const target = isNodeTarget ? "node" : archetype.babel.target;

const targets = archetype.babel.envTargets[target];
console.log(ck`<orange>Babel preset-env compile targets: </><cyan>${JSON.stringify(targets)}</>`);

const useBuiltIns =
!isNodeTarget && archetype.babel.hasMultiTargets
? { useBuiltIns: "entry", corejs: require("core-js/package.json").version.split(".")[0] }
: {};

const presets = [
//
// webpack 4 can handle ES modules now so turn off babel module transformation
// in production mode to allow tree shaking.
// But keep transforming modules to commonjs when not in production mode so tests
// can continue to stub ES modules.
//
[
"@babel/preset-env",
{
modules: isNodeTarget || isProduction || enableDynamicImport ? "auto" : "commonjs",
loose: true,
targets,
...useBuiltIns
}
],
enableTypeScript && "@babel/preset-typescript",
"@babel/preset-react"
];

module.exports = {
presets: presets.filter(x => x),
plugins: plugins.filter(x => x)
};
2 changes: 1 addition & 1 deletion packages/xarc-app-dev/config/env-babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const babelConfigSpec = {
default: {
ie: "8"
},
node: process.versions.node.split(".")[0]
node: { node: process.versions.node.split(".")[0] }
}
},
target: {
Expand Down
11 changes: 10 additions & 1 deletion packages/xarc-app-dev/lib/dev-admin/admin-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ const APP_SERVER_NAME = "your app server";
const DEV_SERVER_NAME = "Electrode webpack dev server";
const PROXY_SERVER_NAME = "Electrode Dev Proxy";

const SERVER_ENVS = {
[APP_SERVER_NAME]: {
XARC_BABEL_TARGET: "node"
},
[DEV_SERVER_NAME]: {},
[PROXY_SERVER_NAME]: {}
};

class AdminServer {
constructor(args, options) {
this._opts = args.opts;
Expand Down Expand Up @@ -214,7 +222,8 @@ class AdminServer {
const start = () => {
const forkOpts = {
env: Object.assign({}, process.env, {
ELECTRODE_ADMIN_SERVER: true
ELECTRODE_ADMIN_SERVER: true,
...SERVER_ENVS[name]
}),
silent: true
};
Expand Down
102 changes: 30 additions & 72 deletions packages/xarc-app/arch-clap.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const optionalRequire = require("optional-require")(require);
require.resolve(`${archetype.devArchetypeName}/package.json`);

const devRequire = archetype.devRequire;
const ck = devRequire("chalker");

const detectCssModule = devRequire("@xarc/webpack/lib/util/detect-css-module");

Expand Down Expand Up @@ -345,29 +346,22 @@ function makeTasks(xclap) {
});
};

const makeBabelRc = (destDir, rcFile, resultFile = ".babelrc.js") => {
const makeBabelConfig = (destDir, rcFile, resultFile = "babel.config.js") => {
destDir = Path.resolve(destDir);

if (!Fs.existsSync(destDir)) return;

// must use posix path to save the path to the archetype's babel rc file
// to use in babel RC's extends option
const archRc = Path.posix.join(archetype.devPkg.name, "config", "babel", rcFile);

const oldFn = Path.join(destDir, ".babelrc");
const fn = Path.join(destDir, resultFile);

if (Fs.existsSync(oldFn)) {
const rc = JSON.parse(Fs.readFileSync(oldFn));
rc.extends = archRc;
Fs.writeFileSync(oldFn, `${JSON.stringify(rc, null, 2)}\n`);
logger.info(`You have old ${oldFn} - please remove it to allow ${resultFile}.`);
} else if (!Fs.existsSync(fn)) {
logger.info(`Generating ${fn} for you - please commit it.`);
const rc = `module.exports = {
extends: "${archRc}"
const newName = Path.join(destDir, resultFile);

if (!Fs.existsSync(newName)) {
console.log(ck`<orange>Generating <cyan>${newName}</> for you - please commit it.</>`);
const babelConfig = `"use strict";
module.exports = function (api) {
api.cache(true);
const config = require("@xarc/app-dev/config/babel/babelrc.js");
return { ...config };
};\n`;
Fs.writeFileSync(fn, rc);
Fs.writeFileSync(newName, babelConfig);
}
};

Expand Down Expand Up @@ -605,9 +599,8 @@ Individual .babelrc files were generated for you in src/client and src/server
);
},

".build.client.babelrc": () => {
makeBabelRc(AppMode.src.dir, "babelrc-client.js");
makeBabelRc(AppMode.src.client, "babelrc-client.js");
".build.babelrc": () => {
makeBabelConfig(process.cwd(), "babelrc.js");
},

".build-lib:delete-babel-ignored-files": {
Expand Down Expand Up @@ -645,23 +638,25 @@ Individual .babelrc files were generated for you in src/client and src/server
".clean.lib:server",
".mk.lib.client.dir",
".mk.lib.server.dir",
".build.client.babelrc",
".build.server.babelrc"
".build.babelrc"
],
task: mkCmd(
`~$babel ${AppMode.src.dir}`,
`--out-dir=${AppMode.lib.dir}`,
`--extensions=${babelCliExtensions}`,
`--source-maps=inline --copy-files`,
`--verbose --ignore=${babelCliIgnore}`
task: xclap.exec(
[
`babel ${AppMode.src.dir}`,
`--out-dir=${AppMode.lib.dir}`,
`--extensions=${babelCliExtensions}`,
`--source-maps=inline --copy-files`,
`--verbose --ignore=${babelCliIgnore}`
],
{ env: { XARC_BABEL_TARGET: "node" } }
),
finally: [".build-lib:delete-babel-ignored-files"]
},

// TODO: to be removed
"build-lib:client": {
desc: false,
dep: [".clean.lib:client", ".mk.lib.client.dir", ".build.client.babelrc"],
dep: [".clean.lib:client", ".mk.lib.client.dir"],
task: () => {
const dirs = AppMode.hasSubApps
? []
Expand Down Expand Up @@ -698,26 +693,10 @@ Individual .babelrc files were generated for you in src/client and src/server
);
},

".build.server.babelrc": () => {
const serverDirs =
scanDir.sync({
dir: AppMode.src.dir,
includeDir: true,
includeRoot: true,
grouping: true,
filterDir: x => x.startsWith("server") && "dirs",
filter: () => false
}).dirs || [];

serverDirs.forEach(x => {
makeBabelRc(x, "babelrc-server.js");
});
},

// TODO: to be removed
"build-lib:server": {
desc: false,
dep: [".clean.lib:server", ".mk.lib.server.dir", ".build.server.babelrc"],
dep: [".clean.lib:server", ".mk.lib.server.dir"],
task: [
mkCmd(
`~$babel ${AppMode.src.server} --out-dir=${AppMode.lib.server}`,
Expand All @@ -729,14 +708,6 @@ Individual .babelrc files were generated for you in src/client and src/server
]
},

".build.test.client.babelrc": () => {
return makeBabelRc("test/client", "babelrc-client.js");
},

".build.test.server.babelrc": () => {
return makeBabelRc("test/server", "babelrc-server.js");
},

check: ["lint", "test-cov"],
"check-ci": ["lint", "test-ci"],
"check-cov": ["lint", "test-cov"],
Expand All @@ -760,13 +731,7 @@ Individual .babelrc files were generated for you in src/client and src/server
devbrk: ["dev --inspect-brk"],
dev: {
desc: "Start your app with watch in development mode",
dep: [
".remove-log-files",
".development-env",
".mk-dist-dir",
".build.client.babelrc",
".build.server.babelrc"
],
dep: [".remove-log-files", ".development-env", ".mk-dist-dir", ".build.babelrc"],
task: function() {
if (!Fs.existsSync(".isomorphic-loader-config.json")) {
Fs.writeFileSync(".isomorphic-loader-config.json", JSON.stringify({}));
Expand Down Expand Up @@ -885,13 +850,9 @@ Individual .babelrc files were generated for you in src/client and src/server
"test-watch-all": xclap.concurrent("server-admin.test", "test-frontend-dev-watch"),

"test-ci": ["test-frontend-ci"],
"test-cov": [
".build.test.client.babelrc",
".build.test.server.babelrc",
"?.karma.test-frontend-cov",
"?.jest.test-frontend-cov",
"test-server-cov"
].filter(x => x),
"test-cov": ["?.karma.test-frontend-cov", "?.jest.test-frontend-cov", "test-server-cov"].filter(
x => x
),
"test-dev": ["test-frontend-dev", "test-server-dev"],

"test-watch": ["test-watch-all"],
Expand Down Expand Up @@ -1135,9 +1096,6 @@ Individual .babelrc files were generated for you in src/client and src/server
}

if (runJest) {
if (testDir) {
makeBabelRc(Path.join(testDir, "client"), "babelrc-client.js");
}
const jestBinJs = require.resolve("jest/bin/jest");
logger.info("Running jest unit tests");

Expand Down