diff --git a/package.json b/package.json index 62c1e0ca6..31fcb8a1f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nativescript", - "version": "7.0.0-rc.55", + "version": "7.0.0-rc.57", "license": "MIT", "scripts": { "setup": "npx rimraf -- hooks node_modules package-lock.json && npm i && ts-patch install && nx run core:setup", diff --git a/packages/core/index.d.ts b/packages/core/index.d.ts index bac3d6db9..423232b1d 100644 --- a/packages/core/index.d.ts +++ b/packages/core/index.d.ts @@ -5,6 +5,7 @@ * the reference path above will get rewritten and break on compilation unless kept here * Once issue is resolve we can remove this index.d.ts from repo and go back to auto generation on tsc */ +export type { NativeScriptConfig } from './config'; export { iOSApplication, AndroidApplication } from './application'; export type { ApplicationEventData, LaunchEventData, OrientationChangedEventData, UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData, AndroidActivityEventData, AndroidActivityBundleEventData, AndroidActivityRequestPermissionsEventData, AndroidActivityResultEventData, AndroidActivityNewIntentEventData, AndroidActivityBackPressedEventData, SystemAppearanceChangedEventData } from './application'; import { systemAppearanceChanged, getMainEntry, getRootView, _resetRootView, getResources, setResources, setCssFileName, getCssFileName, loadAppCss, addCss, on, off, run, orientation, getNativeApplication, hasLaunched, systemAppearance } from './application'; diff --git a/packages/core/package.json b/packages/core/package.json index df37c4229..5103904ad 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -3,7 +3,7 @@ "main": "index", "types": "index.d.ts", "description": "NativeScript Core Modules", - "version": "7.0.0-rc.55", + "version": "7.0.0-rc.57", "homepage": "https://nativescript.org", "repository": { "type": "git", @@ -27,9 +27,8 @@ }, "dependencies": { "css-tree": "^1.0.0-alpha.39", - "@nativescript/hook": "~1.0.0", + "@nativescript/hook": "~2.0.0", "reduce-css-calc": "^2.1.7", - "tns-core-modules": "rc", "tslib": "2.0.0" }, "nativescript": { diff --git a/packages/webpack/helpers/projectFilesManager.js b/packages/webpack/helpers/projectFilesManager.js index 991f6bcbd..28fbcbf6b 100644 --- a/packages/webpack/helpers/projectFilesManager.js +++ b/packages/webpack/helpers/projectFilesManager.js @@ -1,7 +1,7 @@ const path = require("path"); const fs = require("fs"); -const { isTypeScript, isAngular, isVue, isShared, isPlugin } = require("./projectHelpers"); +const { isTypeScript, isAngular, isVue, isReact, isShared, isPlugin } = require("./projectHelpers"); function addProjectFiles(projectDir) { const projectTemplates = getProjectTemplates(projectDir); @@ -71,6 +71,8 @@ function getProjectTemplates(projectDir) { } } else if (isVue({ projectDir })) { templates = getVueTemplates(WEBPACK_CONFIG_NAME); + } else if (isReact({ projectDir })) { + templates = getReactTemplates(WEBPACK_CONFIG_NAME); } else if (isTypeScript({ projectDir })) { templates = getTypeScriptTemplates(WEBPACK_CONFIG_NAME); } else { @@ -104,6 +106,13 @@ function getVueTemplates(webpackConfigName) { }; } +function getReactTemplates(webpackConfigName) { + return { + "webpack.typescript.js": "webpack.typescript.js", + "webpack.react.js": webpackConfigName + }; +} + function getJavaScriptTemplates(webpackConfigName) { return { "webpack.javascript.js": webpackConfigName, diff --git a/packages/webpack/helpers/projectHelpers.js b/packages/webpack/helpers/projectHelpers.js index c4cd68d18..57b6105cd 100644 --- a/packages/webpack/helpers/projectHelpers.js +++ b/packages/webpack/helpers/projectHelpers.js @@ -44,6 +44,13 @@ const isVue = ({ projectDir, packageJson } = {}) => { .some(dependency => dependency === "nativescript-vue"); }; +const isReact = ({ projectDir, packageJson } = {}) => { + packageJson = packageJson || getPackageJson(projectDir); + + return packageJson.dependencies && Object.keys(packageJson.dependencies) + .some(dependency => dependency === "react-nativescript"); +}; + const getPackageJson = projectDir => { const packageJsonPath = getPackageJsonPath(projectDir); const result = readJsonFile(packageJsonPath); @@ -137,6 +144,7 @@ module.exports = { isPlugin, getAngularVersion, isVue, + isReact, isTypeScript, writePackageJson, convertSlashesInPath, diff --git a/packages/webpack/package.json b/packages/webpack/package.json index 255e1362b..a416cf96b 100644 --- a/packages/webpack/package.json +++ b/packages/webpack/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "3.0.0-rc.1", + "version": "3.0.0-rc.2", "main": "index", "description": "Webpack plugin for NativeScript", "homepage": "https://nativescript.org", @@ -60,7 +60,7 @@ "global-modules-path": "~2.3.0", "loader-utils": "~2.0.0", "minimatch": "~3.0.4", - "@nativescript/hook": "~1.0.0", + "@nativescript/hook": "~2.0.0", "nativescript-worker-loader": "~0.12.0", "properties-reader": "~2.0.0", "proxy-lib": "0.4.0", diff --git a/packages/webpack/templates/webpack.react.js b/packages/webpack/templates/webpack.react.js new file mode 100644 index 000000000..27d5912cf --- /dev/null +++ b/packages/webpack/templates/webpack.react.js @@ -0,0 +1,112 @@ +const webpackConfig = require("./webpack.typescript"); +const webpack = require("webpack"); +const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); + +module.exports = (env) => { + env = env || {}; + const hmr = env.hmr; + const production = env.production; + const isAnySourceMapEnabled = !!env.sourceMap || !!env.hiddenSourceMap; + + const babelOptions = { + sourceMaps: isAnySourceMapEnabled ? "inline" : false, + babelrc: false, + presets: [ + // https://github.com/Microsoft/TypeScript-Babel-Starter + "@babel/env", + "@babel/typescript", + "@babel/react" + ], + plugins: [ + ...( + hmr && !production ? + [ + require.resolve('react-refresh/babel') + ] : + [] + ), + ["@babel/plugin-proposal-class-properties", { loose: true }] + ] + }; + + const baseConfig = webpackConfig(env); + + // Remove ts-loader as we'll be using Babel to transpile the TypeScript instead. + baseConfig.module.rules = baseConfig.module.rules.filter((rule) => { + const isTsLoader = rule.use && rule.use.loader === "ts-loader"; + return !isTsLoader; + }); + + // Modify "nativescript-dev-webpack/hmr/hot-loader" to test for .tsx files + // (and also js(x) files, which it should have been doing to begin with!) + baseConfig.module.rules.some(rule => { + const isNativeScriptDevWebpackHotLoader = rule.use === "nativescript-dev-webpack/hmr/hot-loader"; + + if(isNativeScriptDevWebpackHotLoader){ + rule.test = /\.(ts|tsx|js|jsx|css|scss|html|xml)$/; + } + + return isNativeScriptDevWebpackHotLoader; // Break loop once we've found the one. + }); + + baseConfig.module.rules.push( + { + test: /\.[jt]s(x?)$/, + exclude: /node_modules/, + use: [ + { + loader: "babel-loader", + options: babelOptions + } + ], + } + ); + + baseConfig.resolve.extensions = [".ts", ".tsx", ".js", ".jsx", ".scss", ".css"]; + baseConfig.resolve.alias["react-dom"] = "react-nativescript"; + + // Remove ForkTsCheckerWebpackPlugin because, now that we're using Babel, we'll leave type-checking to the IDE instead. + baseConfig.plugins = baseConfig.plugins.filter(plugin => { + const isForkTsCheckerWebpackPlugin = plugin && plugin.constructor && plugin.constructor.name === "ForkTsCheckerWebpackPlugin"; + return !isForkTsCheckerWebpackPlugin; + }); + + // Augment NativeScript's existing DefinePlugin definitions with a few more of our own. + let existingDefinePlugin; + baseConfig.plugins = baseConfig.plugins.filter(plugin => { + const isDefinePlugin = plugin && plugin.constructor && plugin.constructor.name === "DefinePlugin"; + existingDefinePlugin = plugin; + return !isDefinePlugin; + }); + const newDefinitions = { + ...existingDefinePlugin.definitions, + /* For various libraries in the React ecosystem. */ + "__DEV__": production ? "false" : "true", + "__TEST__": "false", + /* + * Primarily for React Fast Refresh plugin, but technically the forceEnable option could be used instead. + * Worth including anyway, as there are plenty of Node libraries that use this flag. + */ + "process.env.NODE_ENV": JSON.stringify(production ? "production" : "development"), + }; + baseConfig.plugins.unshift(new webpack.DefinePlugin(newDefinitions)); + + /** + * Set forceEnable to `true` if you want to use HMR on a production build. + */ + const forceEnable = false; + if(hmr && (!production || forceEnable)){ + baseConfig.plugins.push(new ReactRefreshWebpackPlugin({ + /** + * Maybe one day we'll implement an Error Overlay, but the work involved is too daunting for now. + * @see https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/79#issuecomment-644324557 + */ + overlay: false, + forceEnable, + })); + } else { + baseConfig.plugins = baseConfig.plugins.filter(p => !(p && p.constructor && p.constructor.name === "HotModuleReplacementPlugin")); + } + + return baseConfig; +};