What's `re-start`?
Edit on GitHubReact Native is a framework derived from React that allow to program mobile native apps using Javascript. It’s only focused on Android and iOS, but its popularity has lead to other implementations of its API for other platforms like Windows, macOS or also web. Thing is, although they share the same APIs and source code is (almost) compatible between them, they are not integrated so it would surface difficulties to add a new platform to an existing code, or forcing to have several different projects that could lead to duplicated efforts or diverge the features of them.
re-start is a set of pre-configured templates to create React Native projects that can run both on Android, iOS, web, Windows and Electron from a single source code base, unifying the ports for the different React Native platforms currently available:
- React Native for Android, iOS and appleTV
- react-native-web for web (obviously)
- rnpm-plugin-windows and react-native-windows for Windows 10, Windows 10 Mobile and Xbox One
- Electron (based on
web
platform)
Advantages and disadvantages
The main advantages of this perspective is to allow to have a wider difussion of your project with almost the same effort of developing for just one single platform, while at the same time you can just use standard React Native idioms instead of third-party frameworks. By having a single codebase you can also be sure that all platforms have the same features and behaviour, decreasing the incompatibilities and costs that could arise by having independent projects for each platform (with potentially independent teams, too).
This has some disadvantages, being the obvious one the need to fix the minor diferences between the different platforms and their support of the React Native APIs or particular platform features. The main problem though, is the fact that most React Native components that include native code are targeted only for Android or iOS, not taking in account other platforms like web or Windows. This requires to search for alternatives that include support for the additional platforms or add them ourselves, or if possible, find alternatives written in vanilla Javascript and using the React Native standard components, that have the advantage of being more secure by running inside the Javascript virtual machine instead of executing platform native code. In this aspect, the safest bet to solve these problems is to define the web platform as the “canonical” one and develop your project targeting it first. This platform don’t also makes the development and debug cycle easier and faster (you can use your web browser to debug your app instead of an Android or iOS devices or an emulator), but also force you to find this “pure Javascript” components that will make you sure your project work on all the platforms.
Update process
re-start
was created by Amogh Banta, but in
last weeks project development has slowed down and needed some maintenance, so I
decided to update and clean-up it. The main areas I have been working on were
- removal of duplicated and useless files
- unify code entrypoints
- fix usage of placeholders
- ensure projects work unmodified once they are generated
- and improve support of Windows platform
removal of duplicated and useless files
The diferent templates had the same or similar files duplicated between them,
that make maintenance more dificult. react-native-cli
don’t support to use
inherited templates, nor define a template as dependency of another (a hack to
define a “parent” template) due to usage of the dependencies.json
file, nor
execution of scripts to fix the inheritance by hand. Only solutions that have
been found are to install several templates by hand one on top of previous ones,
generate and publish them with copied files, or use a custom CLI tool (long term
solution planned by Amogh Banta).
The solution that I’ve implemented is the stacked templates. To do so, I removed
the duplicated files, so the devs install first the re-base
template and later
apply the other ones. After that, devs just only need to exec the
finishInstall.js
script at the root of the generated project to do the final
tune-ups and clean the autogenerated useless files like App.windows.js
that
could lead to confussion.
Installing a template using git://
fails due to how npm
works with git
repositories and multirepos (first time in my life I’ve desired it support
them…). Using file://
fails when pointing to a directory since files are not
copied to node_modules
dir but instead used directly, so react-native
cli
fails due to not being able to solve the paths. This also happen when using a
npm pack
tarfile or a local web server pointing to the generated tarfile or
the project package.json
file. It seems to be due to react-native
cli
doesn’t clean-up the template name
when installing from other place than a npm
registry, like a tarfile or a
directory or a scoped package.
Trying to publish the template and install it as a scoped package doesn’t work
because react-native
cli just append the package name to the
react-native-template-
string, fetching it as
react-native-template-@piranna/react-native-template-re-base
instead of
@piranna/react-native-template-re-base
, making it to wrongly think that’s a
Github repository due to the slash and not finding the @
at the beggining. I
could finally install the re-base
template by publishing it on npm
as a new
package, named react-native-template-re-base_piranna
, helping to polute the
npm
registry thanks to this. I’ve open a pull-request to
propose a fix for this.
unify code entrypoints
Instead of having platform specific ones, all the project entrypoints have been
unified except the ones for Electron and web
platform, that need their special
loading process. react-native init
creates an App.js
file, so it’s not
needed to add it and can be used as platforms common example entrypoint.
Electron requires to work that the main
field of package.json
file points to
its entrypoint, so I added
some checkings of the platform and in case the file is not used as Electron
entrypoint, return instead the content of App.js
. On the other hand,
react-scripts start
uses the file at src/index.js
as default entrypoint for
web
platform, and trying to use the App.js
file in the web
platform fails
because react-scripts
can’t use files outside src
folder:
https://gist.github.com/d62cbe56a14f809a127da2c4a20f1943
As proposed by the error message, solution has been to just move App.js
to
src/App.js
as part of the tasks done by the finishInstall.js
script, and
change the references of the other platforms entrypoints to use it, making this
file the app common entrypoint for all the platforms, and the one devs should
only worry about.
fix usage of placeholders
re-start
templates had some hardcoded values that otherwise could be replaced
by the final project ones. After looking for them, I replaced that values for
the correct React Native templates placeholders (HelloWorld
strings
everywhere) so now the correct project names will appear instead of references
to re-start
project.
ensure projects work unmodified once they are generated
The main leit-motiv of re-start
is to create projects that can run on
several platforms, but this was not fully true for the generated projects,
providing some basic config and needing some tune-ups to make this true. I’ve
paid special attention to this point so generated projects can run in all the
re-start
platform unmodified, allowing this to be a reference milestone for
devs and also works as basis to implement some tests and allow auto-upgrade of
the template dependencies. In this aspect, I’ve also fixed Electron platform to
don’t need to have web server running to serve the app files but instead access
them from the filesystem, and also added some npm run
scripts so all the build
steps can be done by executing npm run <platform>
and also it’s available
npm run <platform>:release
to build release outputs (although Electron needs
to have wine
installed to set the Windows executable icon), or you can run
npm run release
to build all the releases at once, so there’s no need to learn
any third party tool.
improve support of Windows platform
As part of checking all platforms are ready to run, Windows platform showed to
need to extra love. This is due to not being one of the core React Native
platforms like Android and iOS nor have its own bundler like web
platform
(that uses webpack
under the hood), so it’s not just a matter of adding the
react-native-windows
package as happens with web
platform and its
react-native-web
package, but instead Windows platform needs to be registered
first in React Native as one of the available platforms.
To do so, what’s needed to be added instead is the rnpm-plugin-windows
package
as a devDependency
, that will enable the Windows platform support in React
Native for that project. After that, exec react-native windows
in the project,
so the Windows runtime files gets generated and the react-native-windows
dependency gets installed. All these steps are already done automatically by
re-start
when you create a new project, so it’s ready to run on Windows
platform just by executing npm run windows
. This command has the problem that
react-native-windows
includes between its dependencies files the nuget.exe
file but without execution permissions. Enabling them by hand and run it on
Linux crashes with some errors that seems related to the lack of some .NET/Mono
libraries, so I needed to exec the npm run windows
command to build the
Windows binary from a Windows virtual machine.
To build React Native apps for the Windows platform, you’ll need to have
installed in your Windows system not only VisualStudio 2017 tools but also the
Windows 10 SDK Build 14393.
Windows binaries need to be signed, so after doing that, if you try to build it
you’ll probably get an error about the included certificate has expired. To fix
that issue, open the project solution file stored at windows/<projectName>.sln
with VisualStudio to
update the signing certificate.
After creating the new certificate, when you’ll try to build the Windows binary
for the first time it will ask you to install the generated certificate in your
system, so just accept it and let the build process to end.
Future work
The most inmediate work is regarding development of unit tests and integration
with Greekeeper to keep the dependencies upgraded and
be sure that the templates are working after that. Since currently it’s not
possible to use local filesystem to serve the templates files (both directly or
as a tarfile), tests for re-start
could make use of nock
to intercept the
HTTP requests for the packages install or start a local npm proxy.
Another future task is to check what libraries are needed to make nuget.exe
to work on Linux, so generation of Windows binaries would not need to be done in
a Windows host, and to add support for
react-native-macos to be able to
generate native OSX binaries. And from a personal joice, create a new React
Native port to render UI components in the terminal console. Why not? :-)
Comment on Twitter
You can leave a comment by replying this tweet.