Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Code sharing at scale: one codebase for web, mo...

Code sharing at scale: one codebase for web, mobile and desktop

React.js and React-Native allow a "learn once write anywhere paradigm". This is great because one tech team can build both your web app and native mobile experience. The problem is developers hate writing things twice. There have been a couple of efforts to build a unifying technology to write an application once and have it work on both web and native. Yet this is not always the best approach.

This talk will cover identifying the best candidates for shared code and a couple of lessons learned while building an app with code sharing as a primary objective — from project setup, through shared infrastructure, all the way up to shared components and styling — and how you can achieve the same thing.

Last but not least, I'll share a couple of thoughts on what's coming down the line!

Matheus Albuquerque

November 26, 2019
Tweet

More Decks by Matheus Albuquerque

Other Decks in Programming

Transcript

  1. CODE SHARING AT SCALE: ONE CODEBASE FOR WEB, MOBILE AND

    DESKTOP Matheus Albuquerque, Front-End Engineer at STRV
  2. CONTEXT • WHY • VELOCITY Often fewer short-term gains due

    to overhead in writing glue code Have to rearchitect existing JavaScript code Tooling is difficult (CI, unit tests etc.) Write code once Possibly long-term gains 8
  3. CONTEXT • WHY • NO PLATFORM SPECIALIZATION An engineer should

    be able to write mobile code for the product without differentiating between Android and iOS Low occurrence of OS-specific problems 9
  4. CONTEXT • CONCERNS • What if I need to implement

    a specific component separately for Web and Native? • How to use React Native-specific libraries? • What about navigation? • How to handle different storage layers? • What not to share? 10
  5. CONTEXT • TYPES OF CODE • DIFFERENT RENDER ENVIRONMENTS 13

    UI Render <div> <View> !== <ul> <FlatList> !== <WebPrimitive> <NativePrimitive> !==
  6. React Native Web • Developed by Nicolas Gallagher (Facebook) •

    Parallel implementation of React Native • Web Equivalents of RN components • Used by Twitter, Major League Soccer, Uber, Flipkart, The Times 15 ReactXP • Developed by the Skype Team (Microsoft) • Abstraction layer over React-DOM and React Native • Wrappers over Web/Native components • Used by Skype CONTEXT • SOLUTIONS • ADDING WEB TO THE EQUATION
  7. 17 Flutter NativeScript Ionic We’re going to mention a couple

    things. CONTEXT • SOLUTIONS React Native Web ReactXP
  8. 18 Flutter NativeScript Ionic We’re going to focus on this

    one. CONTEXT • SOLUTIONS React Native Web ReactXP
  9. • I enjoy having control over the stack and being

    aware of what's happening. I want to: • Customize the installation • Install custom version of modules • Have more control of project dependencies • Use own CI/CD implementation • Use our own React Native modules • We can only use their SDK and packages that don’t require linking • Size (might) matter • Permissions eventually being needed despite the fact the app never needs them 20 CONTEXT • SOLUTIONS • DISCLAIMER
  10. ARCHITECTURE |-- packages/ | |-- mobile/ | |-- shared/ |

    |-- web/ |-- patches/ | |-- react-native-google-signin+2.0.0.patch | |-- ... |-- .eslintrc.js |-- .gitignore |-- .prettierrc.js |-- .stylelintrc |-- README.md |-- commitlint.config.js |-- package.json |-- tsconfig.base.json |-- tsconfig.json |-- yarn.lock 26
  11. ARCHITECTURE |-- packages/ | |-- mobile/ | |-- shared/ |

    |-- web/ |-- patches/ | |-- react-native-google-signin+2.0.0.patch | |-- ... |-- .eslintrc.js |-- .gitignore |-- .prettierrc.js |-- .stylelintrc |-- README.md |-- commitlint.config.js |-- package.json |-- tsconfig.base.json |-- tsconfig.json |-- yarn.lock 27 Each platform code + shared business logic
  12. ARCHITECTURE |-- packages/ | |-- mobile/ | |-- shared/ |

    |-- web/ |-- patches/ | |-- react-native-google-signin+2.0.0.patch | |-- ... |-- .eslintrc.js |-- .gitignore |-- .prettierrc.js |-- .stylelintrc |-- README.md |-- commitlint.config.js |-- package.json |-- tsconfig.base.json |-- tsconfig.json |-- yarn.lock 28 Native library patches
  13. ARCHITECTURE |-- packages/ | |-- mobile/ | |-- shared/ |

    |-- web/ |-- patches/ | |-- react-native-google-signin+2.0.0.patch | |-- ... |-- .eslintrc.js |-- .gitignore |-- .prettierrc.js |-- .stylelintrc |-- README.md |-- commitlint.config.js |-- package.json |-- tsconfig.base.json |-- tsconfig.json |-- yarn.lock 29 Dotfiles and other project-wide stuff
  14. ARCHITECTURE |-- packages/ | |-- mobile/ | |-- shared/ |

    |-- web/ |-- patches/ | |-- react-native-google-signin+2.0.0.patch | |-- ... |-- .eslintrc.js |-- .gitignore |-- .prettierrc.js |-- .stylelintrc |-- README.md |-- commitlint.config.js |-- package.json |-- tsconfig.base.json |-- tsconfig.json |-- yarn.lock 30 Shared config which can be extended
  15. ARCHITECTURE • SHARED • TYPES OF CODE 38 UI Render

    Configuration API / Formatting Business Logic
  16. ARCHITECTURE • SHARED • TYPES OF CODE 39 UI Render

    Business Logic Configuration API / Formatting
  17. ARCHITECTURE • SHARED • TYPES OF CODE 40 Business Logic

    Environment independent If a user can only add 20 items to their basket, this rule will hold true in web and native equally
  18. ARCHITECTURE • SHARED • TYPES OF CODE 41 Configuration Config

    files, translation files and most constant data are not render environment specific If I update a translation on my app, it’s very likely I want that change rolled out on the web app too
  19. ARCHITECTURE • SHARED • TYPES OF CODE 42 Configuration Shared

    config object Web Config Object Native Config Object
  20. ARCHITECTURE • SHARED • TYPES OF CODE 43 Configuration Shared

    config object Web Config Object Native Config Object { ...sharedConfig, mobileSpecificConfig: '...', }
  21. ARCHITECTURE • SHARED • TYPES OF CODE 44 API /

    Formatting API calls, authentication and formatting of request and response data If we make a POST to a REST API on web, it’s very likely to be the same POST on native
  22. TOOLS • React Navigation V3 as a universal routing strategy

    • patch-package to keep me safe and sound from Xcode • Yarn Workspaces to enable our monorepo strategy 48
  23. TOOLS • REACT NAVIGATION V3 • @reach/router has no React

    Native support • react-router-native lacks screen transitions, back-button support, modals, navbars and other important stuff • Started by making a few crazy combinations: • react-router-dom + react-router-native • react-router-dom + react-navigation • … • Currently using React Navigation on the Web • This has not yet been widely used in production and it is considered to be experimental 49
  24. TOOLS • PATCH-PACKAGE 51 • patch-package lets app authors instantly

    make and keep fixes to npm dependencies • My case: • Had to change a few files on the library’s iOS code (XCode stuff) • It was not worthy to submit a PR on the library, tho (the problem was literally on our machines™) • Having each member of the team changing the same stuff is simply out of consideration • Seems to be an accepted pattern on React Native community
  25. TOOLS • YARN WORKSPACES • Let you organize your project

    codebase using a monolithic repository • React is a good example of an open-source project that is monorepo. Also, React uses Yarn workspaces to achieve that • nohoist FTW • Currently: mobile, web and shared packages • Future plans: desktop (electron?) and back-end (maybe) 52
  26. CHALLENGES • Lack of real-world-scenarios content related to React Native

    Web on the web (e.g. navigation) • (unexpected) Lack of documented stuff on popular projects (e.g. Webpack and Metro) • react-native-web supports most of the react-native API, but a few pieces are missing 54
  27. CHALLENGES • UNSUPPORTED APIs react-native-web supports most of the react-native

    API, but a few pieces are missing like • Alert • Modal • RefreshControl • WebView 58
  28. TIPS • Navigation may be a bit of a challenge;

    you can use something like react-navigation which recently added web support or you can try using two different navigators between and mobile, in case you want the best of both worlds by compromising some code sharing • To install new dependencies, use the command yarn workspace <package> add <library> from the root directory • To run a script from a package, run yarn workspace <package> start, for example • To run a script from all packages, run yarn workspaces run <script> 60
  29. TIPS • If you plan sharing code with the server,

    I recommend creating a core package that only contain logic and helper functions (no UI-related code); • For Next.js, you can check their official example with react-native-web • For native windows, you can try react-native-windows; • For native macOS, you can the new Apple Project Catalyst, but support for it is not 100% there yet 61
  30. TL;DR • LESSONS LEARNT • Code sharing is a great

    advantage of React and React Native • Share your non-design render code • Your mobile app and web app (probably) should have different experiences • HOCs / hooks help sharing component logic 65
  31. TL;DR • LESSONS LEARNT "Web, mobile web and native application

    environments all require a specific design and user experience." - Matheus 66
  32. TL;DR • LESSONS LEARNT 68 It’s worth noting that we’re

    not chasing “write once, run anywhere.” Different platforms have different looks, feels, and capabilities, and as such, we should still be developing discrete apps for each platform, but the same set of engineers should be able to build applications for whatever platform they choose, without needing to learn a fundamentally different set of technologies for each. We call this approach “learn once, write anywhere.”
  33. TL;DR • THE FUTURE 71 Simple Stuff • A couple

    API calls / data fetching • Not too complex lifecycle • Simple Navigation/Routing
  34. TL;DR • THE FUTURE • IONIC (CAPACITOR) 74 • Wraps

    the web app in a WebView • It injects a “bridge” into the app running in the webview, that connects the code of the web app and the code of the native part so these can interact • For Progressive Web Apps Capacitor provides fallback implementations to native functionality not present • Capacitor achieves true cross-platform and portable functionality with 100% code sharing by providing a consistent API • Backward compatible* with Cordova
  35. TL;DR • THE FUTURE • IONIC (CAPACITOR) 75 • Native

    Progressive Web Apps built with Capacitor can be used on all the relevant platforms: • iOS • Android • Browsers (Progressive Web Apps) • Windows, macOS, Linux (via Electron)
  36. TL;DR • THE FUTURE • IONIC (CAPACITOR) 76 Accessibility App

    Background Task Browser Camera Clipboard Console Device Filesystem Geolocation Haptics Keyboard Local Notifications Modals Motion Network Push Notifications Share Splash Screen Status Bar Storage Toast
  37. TL;DR • THE FUTURE • IONIC (CAPACITOR) 77 Accessibility App

    Background Task Browser Camera Clipboard Console Device Filesystem Geolocation Haptics Keyboard Local Notifications Modals Motion Network Push Notifications Share Splash Screen Status Bar Storage Toast + Community Plugins
  38. TL;DR • THE FUTURE • FLUTTER (SKIA) 83 • Fast

    startup and execution of an app are the benefits of compilation to native code • The UI is refreshed at 60fps – mostly using the GPU – and every pixel on the screen is owned by the Skia canvas which leads to a smooth, highly customizable UI • The same hardware-accelerated graphics engine that underpins Chrome and Android