From b2ce0402c3977603d531262e1f303ca196e69f77 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 17 Nov 2020 17:25:34 +0100 Subject: [PATCH] feat: basic ract config --- .../__snapshots__/react.spec.ts.snap | 268 ++++++++++++++++++ .../__tests__/configuration/react.spec.ts | 21 ++ packages/webpack5/src/configuration/react.ts | 35 +++ 3 files changed, 324 insertions(+) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/react.spec.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap new file mode 100644 index 000000000..287f56414 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -0,0 +1,268 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`react configuration for android 1`] = ` +"{ + mode: 'development', + resolve: { + symlinks: true, + alias: { + '~/package.json': 'package.json', + '~': 'appFullPath', + '@': 'appFullPath', + 'react-dom': 'react-nativescript' + }, + extensions: [ + '.tsx' + ] + }, + resolveLoader: { + modules: [ + '@nativescript/webpack/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: /\\\\.(ts|tsx)$/, + use: [ + /* config.module.rule('ts').use('react-hmr') */ + { + loader: 'babel-loader', + options: { + sourceMaps: 'inline', + babelrc: false, + plugins: [ + 'react-refresh/babel' + ] + } + }, + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader' + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('css-loader') */ + { + loader: 'css-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('scss-loader') */ + { + loader: 'scss-loader' + } + ] + } + ] + }, + plugins: [ + /* config.plugin('clean') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + 'platforms/android/app/src/main/assets/app/**/*' + ], + verbose: true + } + ), + /* config.plugin('define') */ + new DefinePlugin( + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process', + __DEV__: 'true', + __TEST__: 'false', + 'process.env.NODE_ENV': '\\"development\\"' + } + ), + /* config.plugin('copy') */ + new CopyPluginTemp( + { + patterns: [] + } + ), + /* config.plugin('watch-state-logger') */ + new WatchStateLoggerPlugin() + ], + entry: { + bundle: [ + 'todo/main' + ] + } +}" +`; + +exports[`react configuration for ios 1`] = ` +"{ + mode: 'development', + resolve: { + symlinks: true, + alias: { + '~/package.json': 'package.json', + '~': 'appFullPath', + '@': 'appFullPath', + 'react-dom': 'react-nativescript' + }, + extensions: [ + '.tsx' + ] + }, + resolveLoader: { + modules: [ + '@nativescript/webpack/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: /\\\\.(ts|tsx)$/, + use: [ + /* config.module.rule('ts').use('react-hmr') */ + { + loader: 'babel-loader', + options: { + sourceMaps: 'inline', + babelrc: false, + plugins: [ + 'react-refresh/babel' + ] + } + }, + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader' + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('css-loader') */ + { + loader: 'css-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('scss-loader') */ + { + loader: 'scss-loader' + } + ] + } + ] + }, + plugins: [ + /* config.plugin('clean') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + 'platforms/ios/[todo]/app/**/*' + ], + verbose: true + } + ), + /* config.plugin('define') */ + new DefinePlugin( + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process', + __DEV__: 'true', + __TEST__: 'false', + 'process.env.NODE_ENV': '\\"development\\"' + } + ), + /* config.plugin('copy') */ + new CopyPluginTemp( + { + patterns: [] + } + ), + /* config.plugin('watch-state-logger') */ + new WatchStateLoggerPlugin() + ], + entry: { + inspector_modules: [ + 'tns_modules/@nativescript/core/inspector_modules' + ], + bundle: [ + 'todo/main' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/react.spec.ts b/packages/webpack5/__tests__/configuration/react.spec.ts new file mode 100644 index 000000000..d6e86ba71 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/react.spec.ts @@ -0,0 +1,21 @@ +import { __react } from '@nativescript/webpack'; + +// todo: maybe mock baseConfig as we test it separately? +// import Config from 'webpack-chain' +// jest.mock('../../src/configuration/base', () => () => { +// return new Config() +// }) + +describe('react configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + expect( + __react({ + [platform]: true, + }).toString() + ).toMatchSnapshot(); + }); + } +}); diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index 7e62761fe..c759a5d0a 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -1,10 +1,45 @@ import base from './base'; import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; +import { merge } from 'webpack-merge'; // todo: add base configuration for react export default function (env: IWebpackEnv): Config { const config = base(env); + // todo: use env + let isAnySourceMapEnabled = true; + let production = false; + + config.resolve.extensions.prepend('.tsx'); + config.resolve.alias.set('react-dom', 'react-nativescript'); + + config.module + .rule('ts') + .test(/\.(ts|tsx)$/) + .use('react-hmr') + .loader('babel-loader') + .before('ts-loader') + .options({ + sourceMaps: isAnySourceMapEnabled ? 'inline' : false, + babelrc: false, + plugins: ['react-refresh/babel'], + }); + + config.plugin('define').tap((args) => { + args[0] = merge(args[0], { + /** For various libraries in the React ecosystem. */ + __DEV__: production ? 'false' : 'true', + __TEST__: 'false', + /** + * Primarily for React Fast Refresh plugin, but technically the allowHmrInProduction 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'), + }); + + return args; + }); + return config; }