If you're a web developer accustomed to the simplicity of Vue.js, learning a whole new language (or two) to develop native mobile apps for iOS and Android may seem daunting. While you can use React Native to develop for mobile using JavaScript, there will still be a steep learning curve unless you're already familiar with React.
Enter NativeScript: it's another open source framework for native mobile app development using JavaScript (or TypeScript), with support for Vue and Angular syntax. The apps you build with it aren't web-based imitations; NativeScript uses JavaScript Virtual Machines on Android and iOS to run your app, and provides access to native APIs through its core modules, translating your JavaScript code into Java for Android, and Objective-C for iOS.
If you're already familiar with Vue, you'll get to take advantage of your existing Vue knowledge and experience when working with NativeScript-Vue. Your templates will look a little different—there's no div
element in NativeScript, for example—but generally, you'll build your app using very familiar Vue syntax, and with plugins like Vuex. It's even possible to share some code between web and mobile platforms in the same codebase.
In this post, we'll configure our environment for NativeScript development on iOS, and create a basic NativeScript-Vue app using Tailwind CSS that can be deployed to iOS and Android devices.
Prerequisites:
six
packageNote that iOS apps can only be built on macOS machines, but if you work on Windows or Linux, NativeScript provides a cloud-based platform called Sidekick that can get you up and running.
To install the necessary dependencies, run the commands below (more detailed instructions are available in the NativeScript macOS setup article):
brew install node@10sudo gem install xcodeprojsudo gem install cocoapodspod setupsudo easy_install pippip install six
Install the NativeScript CLI using NPM:
npm install -g nativescript
Now you can run the system configuration tool, using the command tns doctor
, to verify your setup and identify any problems that need to be fixed. (tns
stands for "Telerik NativeScript"; Telerik is the company that supports NativeScript's development.) When prompted to configure cloud and/or local builds, select "Skip this step and configure manually".
tns doctor
If there are any errors related to NativeScript or iOS development, follow the provided instructions to fix them. Ignore any Android errors; we won't need Android virtual devices just yet.
NativeScript-Vue projects can be created using Vue CLI, just like regular Vue apps (see: NativeScript-Vue Quick Start). Install Vue CLI and initialize your new project:
npm install -g @vue/cli @vue/cli-initvue init nativescript-vue/vue-cli-template hello-world
The init
command will prompt you for some details about your project. You can customize these options or just accept the defaults; everything here can be changed later. When it's finished, cd
into the project folder and install NPM dependencies:
cd hello-worldnpm install
NativeScript supports using CSS in its mobile apps—but not all CSS properties and values are supported, and most values use different units of measurement. This means we can't just import Tailwind the usual way, but there are two options: either create a NativeScript-compatible Tailwind config file overriding any unsupported properties & units, or—better yet—use the NativeScript Tailwind plugin which ships with a NativeScript-compatible default config file.
Install NativeScript Tailwind as a dev dependency:
npm install -D nativescript-tailwind
Import the pre-built Tailwind CSS file in app/app.scss
, which NativeScript loads on all pages by default:
@import "nativescript-tailwind/dist/tailwind";
Note: To keep this tutorial simple we're using the default build, but you can also generate custom builds using
npx nativescript-tailwind tailwind.config.js
. See my config file PR for more information.
We're ready to build our app! NativeScript will make use of Xcode's iOS Simulator feature to run our app on a simulated iOS device:
tns run ios
This command is similar to npm run watch
; you can leave it running in a terminal window during development and it will rebuild the app automatically when you save a file. Hot module reloading is also enabled by default, so most changes will appear instantly without needing to re-compile the app.
Note: You can choose which iOS device to simulate in the Simulator app menu, under Hardware > Device.
Next, open app/components/App.vue
. This is your root component, and the landing page of your mobile app.
You'll notice this component uses <Page>
as its outer element—your app runs in a <Frame>
element (open app/main.js
to see it in action), which can contain <Page>
elements to denote individual pages. In NativeScript, navigating to a new <Page>
is like navigating to a new URL.
Let's add a basic, table-like layout to the landing page using NativeScript's <GridLayout>
element. We'll start with one column sized to fill all the available space (columns="*"
), and three rows with the middle one auto-sized to its content (rows="*, auto, *"
):
<template> <Page class="bg-blue-100"> <ActionBar class="text-white bg-blue-900" title="Welcome to NativeScript-Vue!"/> <GridLayout columns="*" rows="*, auto, *" class="mx-8 text-center"> <Label col="0" row="0" class="text-xl font-bold text-blue-800" :text="msg"/> <Button col="0" row="1" class="py-3 mx-8 bg-blue-200 rounded" text="Click Me!" @tap="msg = 'Hi Mom'"/> </GridLayout> </Page></template> <script> export default { data() { return { msg: 'Hello World', } } }</script>
Assuming you left the command tns run ios
running, you should see "Hello World" and a "Click Me!" button appear on your homescreen, styled with Tailwind classes.
NativeScript provides several other types of layouts to arrange content sections, including <FlexboxLayout>
which behaves similarly to CSS's Flexbox. For example, if we wanted to mimic the behavior of Tailwind's <div class="flex justify-around">
we could use the justifyContent
attribute:
<GridLayout columns="*" rows="*, auto, *"> <FlexboxLayout col="0" row="1" justifyContent="space-around"> <Label class="text-xl font-bold text-blue-800" :text="msg"/> <Button class="px-4 py-2 bg-blue-200 rounded" text="Click Me!" @tap="msg = 'Hi Mom'"/> </FlexboxLayout></GridLayout>
Note: Each nested layout generates a new view "layer", so complex layouts can be costly to render. Keep your layouts simple for optimal performance.
Now that we're familiar with NativeScript layouts, let's add a second page to our app. Create a new file app/components/Page2.vue
and put a basic layout in it:
<template> <Page class="bg-green-600"> <ActionBar class="text-white bg-blue-900" title="Page Two"/> <GridLayout columns="*" rows="*"> <Label col="0" row="0" class="text-center text-white" text="Now we're on page 2"/> </GridLayout> </Page></template>
To route to this new page, we'll need to use the built-in method $navigateTo
—Vue Router isn't compatible with NativeScript's Frame/Page navigation.
Back in App.vue
, import the new component and set it to a data
property, then navigate to it using the button's @tap
event:
<template> <Page class="bg-blue-100"> <ActionBar class="text-white bg-blue-900" title="Welcome to NativeScript-Vue!"/> <GridLayout columns="*" rows="*, auto, *" class="mx-8 text-center"> <Label col="0" row="0" class="text-xl font-bold text-blue-800" :text="msg"/> <Button col="0" row="1" class="py-2 mx-8 bg-blue-200 rounded" text="Click Me!" @tap="$navigateTo(page2)" /> </GridLayout> </Page></template> <script> import Page2 from './Page2' export default { data() { return { msg: 'Hello World', page2: Page2, } } }</script>
Now clicking the button takes us to the Page2 component.
Congratulations! You've built your first mobile app with NativeScript-Vue. Though we haven't tried it on an Android virtual device yet (they're slightly tougher to configure than iOS devices on a Mac), your NativeScript app is ready to be compiled for both platforms, and includes tooling to assist in publishing to the App Store and Google Play Store.
We appreciate your interest.
We will get right back to you.