Removing Short Imports in NativeScript, the Easy Way (with VS Code)
Tags: nativescript, vscode, regex, javascript
Published: 2019-07-17 03:42:58

As NativeScript continues to evolve, some of the features that made sense in 2015 are creating more trouble than they're worth in 2019. One such feature is the so called "short import."

Short imports were intended to improve the developer experience by saving a few key strokes. Instead of this:

```typescript
import { device } from 'tns-core-modules/platform'
```
A developer could simply use:
```typescript
import { device } from 'platform'
```
It's convenient, but it has created unintended side effects. And with great tooling like VS Code that can automatically add imports, the value of this feature low.

So, now it's deprecated (as of {N} 5.2). [Read all about it on the NativeScript blogs](https://www.nativescript.org/blog/say-goodbye-to-short-imports-in-nativescript).

## Now what?
While short imports still work, they will become a real problem with NativeScript 6.0, when webpack becomes the default and only available {N} build system. Webpack expects the full import path, so short imports quickly cause webpack problems.

But if you are maintaining an app that has been around for a while, removing short imports could be quite a chore. In my case, the app I was updating had more than 275 short imports to fix!

I started to fix the imports manually and _quickly_ realized that was a mistake.

If only there was a way to automatically fix all these imports...

## VS Code (and RegEx) to the rescue
Everyone knows that [VS Code has great search and replace tools](https://code.visualstudio.com/docs/editor/codebasics?WT.mc_id=devto-blog-toanglin#_search-across-files), but what may not be as obvious is that you can use regular expressions in the search _and_ replace. Simply toggle "Use Regular Expressions" on and use standard JavaScript regex in the Search, and use `$1`, `$2`, etc to include matching groups in the Replace.

_NOTE: To run really advanced regex searches with backreferences and lookaround (like we'll do today) does require a setting change in VS Code. Go to Settings > Features > Search > Use PCRE2 and check the box to enable these extra capabilities. [See the VS Code docs for more context](https://code.visualstudio.com/docs/editor/codebasics?WT.mc_id=devto-blog-toanglin#_search-across-files)._

And I know, I know. If you have a problem and use RegEx to solve it, now you have two problems. But it beats the tedious alternative.

### RegEx to find short imports
The trick to building the right regular expression for this task is trying find short imports for things that _should_ have the `tns-core-modules` prefix while _avoiding_ imports for "non-core" modules AND imports that already have the correct long format.

Fortunately, most NativeScript modules follow a similar convention:

- Core modules use "plain" names with no prefix (like `application` or `ui/layout`)
- Non-core modules usually prefix the module name with `nativescript-` or `ns-`
- Local modules referenced by path usually start with `./` or `../` or `~/`

By example, we want to FIND imports that look like this:

- `import * as imageSource from "image-source";`
- `import * as util from "utils/utils";`
- `import { Image } from "ui/image";`

While AVOIDING imports that look like this:

- `import { Settings } from "../models/app-models";`
- `import * as firebase from "nativescript-plugin-firebase";`
- `import { Color } from "tns-core-modules/color/color";`

AND THEN, when we have a match, we want to insert "`tns-core-modules/`" in front of the import path while keeping the rest of the line the same.

Put it all together, and we get this search regex:

```javascript
(from \")(?!nativescript)(?!ns)(?!tns-core-modules)((?:[\w\-\/])+)(\")
```
Since regex always looks like a cat walked across your keyboard, let's explain in english:

- Start finding imports by searching for `from "` (including the quote) (and store in matching group 1)...
- Followed by any number of word characters OR `-` (dashes) OR `/` (whacks)(and store in matching group 2)...
- BUT ignore if the matching group contains the words `nativescript` or `ns` or `tns-core-modules`

    - These are likely non-core modules OR imports that already have the correct long format

- And finally, match the trailing `"` (quote)

This combo does a remarkably accurate job of finding the imports we want while ignoring everything else. You can [play with a working version of this regex using Regexr in your browser](https://regexr.com/4hj93) to experiment with what it matches and misses.

When running the search in VS Code, to avoid false positives, you obviously also want to exclude files and folders that are not part of your code, like `node_modules`, `platforms`, `*.js` (assuming you're using TypeScript), `.git`.

### Replace syntax
When the search finds a match to this pattern, it will create three matching groups with these values:

1. `from "`
2. `[name of matched module]`
3. `"`

For example, when the following line is matched:

```typescript
import { Image } from "ui/image";
```
The matching groups will contain:
1. `from "`
2. `ui/image`
3. `"`

We want to insert `tns-core-modules/` between group 1 and group 2. Using VS Code, our replace syntax is:
```javascript
$1tns-core-modules/$2$3
```
Boom! Job done. Almost...

## Another search and replace pass
If you're using the plain JavaScript `require()` syntax to import modules, you clearly need a different search pattern. Even in my TypeScript-based app, I had a handful of imports done with `require()` for reasons specific to module implementation.

Conceptually, the search regex we need is similar to above:
```javascript
(require\(\")(globals)+(\"\))
```

This pattern matches:

1. `require("`
2. `globals`
3. `")`

You could modify the "globals" pattern if you need a wider search. In my case, this was the only `require()` in my app that needed the `tns-core-modules` prefix.

The replace pattern is the same as before:
```javascript
$1tns-core-modules/$2$3
```
## Wrap up
Hopefully you've learned two things in this post:

1. Eliminating short imports in your NativeScript app doesn't have to be tedious manual process
2. VS Code search and replace is REALLY powerful when combined with regex and matching groups