diff --git a/packages/xarc-app-dev/config/babel/babelrc-server.js b/packages/xarc-app-dev/config/babel/babelrc-server.js index 68db7a13e9..d5bf50b040 100644 --- a/packages/xarc-app-dev/config/babel/babelrc-server.js +++ b/packages/xarc-app-dev/config/babel/babelrc-server.js @@ -22,7 +22,7 @@ module.exports = { [ "@babel/preset-env", { - targets: { node } + targets: node } ], enableTypeScript && "@babel/preset-typescript", diff --git a/packages/xarc-app-dev/config/babel/babelrc.js b/packages/xarc-app-dev/config/babel/babelrc.js new file mode 100644 index 0000000000..8bd0c84150 --- /dev/null +++ b/packages/xarc-app-dev/config/babel/babelrc.js @@ -0,0 +1,170 @@ +"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 basePlugins = [ + ...(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 + // } + // ], + "transform-node-env-inline", + "babel-plugin-lodash", + "@babel/plugin-transform-runtime", + addFlowPlugin && [ + "@babel/plugin-transform-flow-strip-types", + { requireDirective: flowRequireDirective } + ] +]; + +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`\nNotice: ${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 plugins = basePlugins.concat( + // test env + isTest && ["babel-plugin-dynamic-import-node"], + // production env + isProduction && [ + "@babel/plugin-transform-react-constant-elements", + [ + "babel-plugin-transform-react-remove-prop-types", + { + removeImport: true + } + ] + ], + // css module support + 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" + } + } + } + ] + ], + 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`Babel preset-env compile targets: ${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) +}; diff --git a/packages/xarc-app-dev/config/env-babel.js b/packages/xarc-app-dev/config/env-babel.js index c56d09a055..aabcf648e1 100644 --- a/packages/xarc-app-dev/config/env-babel.js +++ b/packages/xarc-app-dev/config/env-babel.js @@ -24,7 +24,7 @@ const babelConfigSpec = { default: { ie: "8" }, - node: process.versions.node.split(".")[0] + node: { node: process.versions.node.split(".")[0] } } }, target: { diff --git a/packages/xarc-app/arch-clap.js b/packages/xarc-app/arch-clap.js index 3e5345f1d2..38d4c08de2 100644 --- a/packages/xarc-app/arch-clap.js +++ b/packages/xarc-app/arch-clap.js @@ -605,9 +605,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": () => { + makeBabelRc(AppMode.src.dir, "babelrc.js"); }, ".build-lib:delete-babel-ignored-files": { @@ -645,15 +644,17 @@ 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"] }, @@ -661,7 +662,7 @@ Individual .babelrc files were generated for you in src/client and src/server // 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 ? [] @@ -698,26 +699,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}`, @@ -729,14 +714,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"], @@ -760,13 +737,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({})); @@ -885,13 +856,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"], @@ -1135,9 +1102,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");