Skip to content

Commit edb2ca3

Browse files
authored
fix(cli): migrate v1 plugins NPM packages (#10794)
1 parent 02b2f96 commit edb2ca3

File tree

5 files changed

+146
-18
lines changed

5 files changed

+146
-18
lines changed

.changes/migrate-v1-plugin-npm.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"tauri-cli": patch:bug
3+
"@tauri-apps/cli": patch:bug
4+
---
5+
6+
Migrate v1 plugins NPM packages.

tooling/cli/Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tooling/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ tempfile = "3"
115115

116116
[dev-dependencies]
117117
insta = "1"
118+
pretty_assertions = "1"
118119

119120
[target."cfg(windows)".dependencies.windows-sys]
120121
version = "0.59"

tooling/cli/src/helpers/npm.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,40 @@ impl PackageManager {
117117
Ok(())
118118
}
119119

120+
pub fn remove<P: AsRef<Path>>(&self, dependencies: &[String], app_dir: P) -> crate::Result<()> {
121+
let dependencies_str = if dependencies.len() > 1 {
122+
"dependencies"
123+
} else {
124+
"dependency"
125+
};
126+
log::info!(
127+
"Removing NPM {dependencies_str} {}...",
128+
dependencies
129+
.iter()
130+
.map(|d| format!("\"{d}\""))
131+
.collect::<Vec<_>>()
132+
.join(", ")
133+
);
134+
135+
let status = self
136+
.cross_command()
137+
.arg(if *self == Self::Npm {
138+
"uninstall"
139+
} else {
140+
"remove"
141+
})
142+
.args(dependencies)
143+
.current_dir(app_dir)
144+
.status()
145+
.with_context(|| format!("failed to run {self}"))?;
146+
147+
if !status.success() {
148+
anyhow::bail!("Failed to remove NPM {dependencies_str}");
149+
}
150+
151+
Ok(())
152+
}
153+
120154
pub fn current_package_version<P: AsRef<Path>>(
121155
&self,
122156
name: &str,

tooling/cli/src/migrate/migrations/v1/frontend.rs

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,26 @@ const MODULES_MAP: phf::Map<&str, &str> = phf::phf_map! {
5252
"@tauri-apps/api/process" => "@tauri-apps/plugin-process",
5353
"@tauri-apps/api/shell" => "@tauri-apps/plugin-shell",
5454
"@tauri-apps/api/updater" => "@tauri-apps/plugin-updater",
55+
// v1 plugins to v2
56+
"tauri-plugin-sql-api" => "@tauri-apps/plugin-sql",
57+
"tauri-plugin-store-api" => "@tauri-apps/plugin-store",
58+
"tauri-plugin-upload-api" => "@tauri-apps/plugin-upload",
59+
"tauri-plugin-fs-extra-api" => "@tauri-apps/plugin-fs",
60+
"tauri-plugin-fs-watch-api" => "@tauri-apps/plugin-fs",
61+
"tauri-plugin-autostart-api" => "@tauri-apps/plugin-autostart",
62+
"tauri-plugin-websocket-api" => "@tauri-apps/plugin-websocket",
63+
"tauri-plugin-positioner-api" => "@tauri-apps/plugin-positioner",
64+
"tauri-plugin-stronghold-api" => "@tauri-apps/plugin-stronghold",
65+
"tauri-plugin-window-state-api" => "@tauri-apps/plugin-window-state",
66+
"tauri-plugin-authenticator-api" => "@tauri-apps/plugin-authenticator",
5567
};
5668
const JS_EXTENSIONS: &[&str] = &["js", "mjs", "jsx", "ts", "mts", "tsx", "svelte", "vue"];
5769

58-
/// Returns a list of paths that could not be migrated
70+
/// Returns a list of migrated plugins
5971
pub fn migrate(app_dir: &Path) -> Result<Vec<String>> {
6072
let mut new_npm_packages = Vec::new();
6173
let mut new_plugins = Vec::new();
74+
let mut npm_packages_to_remove = Vec::new();
6275

6376
let pre = env!("CARGO_PKG_VERSION_PRE");
6477
let npm_version = if pre.is_empty() {
@@ -92,7 +105,12 @@ pub fn migrate(app_dir: &Path) -> Result<Vec<String>> {
92105
let ext = path.extension().unwrap_or_default();
93106
if JS_EXTENSIONS.iter().any(|e| e == &ext) {
94107
let js_contents = std::fs::read_to_string(path)?;
95-
let new_contents = migrate_imports(path, &js_contents, &mut new_plugins)?;
108+
let new_contents = migrate_imports(
109+
path,
110+
&js_contents,
111+
&mut new_plugins,
112+
&mut npm_packages_to_remove,
113+
)?;
96114
if new_contents != js_contents {
97115
fs::write(path, new_contents)
98116
.with_context(|| format!("Error writing {}", path.display()))?;
@@ -101,9 +119,16 @@ pub fn migrate(app_dir: &Path) -> Result<Vec<String>> {
101119
}
102120
}
103121

104-
new_npm_packages.sort();
105-
new_npm_packages.dedup();
122+
if !npm_packages_to_remove.is_empty() {
123+
npm_packages_to_remove.sort();
124+
npm_packages_to_remove.dedup();
125+
pm.remove(&npm_packages_to_remove, app_dir)
126+
.context("Error removing npm packages")?;
127+
}
128+
106129
if !new_npm_packages.is_empty() {
130+
new_npm_packages.sort();
131+
new_npm_packages.dedup();
107132
pm.install(&new_npm_packages, app_dir)
108133
.context("Error installing new npm packages")?;
109134
}
@@ -115,6 +140,7 @@ fn migrate_imports<'a>(
115140
path: &'a Path,
116141
js_source: &'a str,
117142
new_plugins: &mut Vec<String>,
143+
npm_packages_to_remove: &mut Vec<String>,
118144
) -> crate::Result<String> {
119145
let mut magic_js_source = MagicString::new(js_source);
120146

@@ -158,31 +184,35 @@ fn migrate_imports<'a>(
158184
if let Statement::ImportDeclaration(stmt) = import {
159185
let module = stmt.source.value.as_str();
160186

161-
// skip parsing non @tauri-apps/api imports
162-
if !module.starts_with("@tauri-apps/api") {
163-
continue;
164-
}
165-
166187
// convert module to its pluginfied module or renamed one
167188
// import { ... } from "@tauri-apps/api/window" -> import { ... } from "@tauri-apps/api/webviewWindow"
168189
// import { ... } from "@tauri-apps/api/cli" -> import { ... } from "@tauri-apps/plugin-cli"
169-
if let Some(&module) = MODULES_MAP.get(module) {
190+
if let Some(&new_module) = MODULES_MAP.get(module) {
170191
// +1 and -1, to skip modifying the import quotes
171192
magic_js_source
172193
.overwrite(
173194
script_start + stmt.source.span.start as i64 + 1,
174195
script_start + stmt.source.span.end as i64 - 1,
175-
module,
196+
new_module,
176197
Default::default(),
177198
)
178199
.map_err(|e| anyhow::anyhow!("{e}"))
179200
.context("failed to replace import source")?;
180201

181202
// if module was pluginified, add to packages
182-
let module = module.split_once("plugin-");
183-
if let Some((_, module)) = module {
184-
new_plugins.push(module.to_string());
203+
if let Some(plugin_name) = new_module.strip_prefix("@tauri-apps/plugin-") {
204+
new_plugins.push(plugin_name.to_string());
185205
}
206+
207+
// if the module is a v1 plugin, we should remove it
208+
if module.starts_with("tauri-plugin-") {
209+
npm_packages_to_remove.push(module.to_string());
210+
}
211+
}
212+
213+
// skip parsing non @tauri-apps/api imports
214+
if !module.starts_with("@tauri-apps/api") {
215+
continue;
186216
}
187217

188218
let Some(specifiers) = &mut stmt.specifiers else {
@@ -317,6 +347,7 @@ fn migrate_imports<'a>(
317347
mod tests {
318348

319349
use super::*;
350+
use pretty_assertions::assert_eq;
320351

321352
#[test]
322353
fn migrates_vue() {
@@ -376,8 +407,15 @@ const appWindow = getCurrentWebviewWindow()
376407
"#;
377408

378409
let mut new_plugins = Vec::new();
410+
let mut npm_packages_to_remove = Vec::new();
379411

380-
let migrated = migrate_imports(Path::new("file.vue"), input, &mut new_plugins).unwrap();
412+
let migrated = migrate_imports(
413+
Path::new("file.vue"),
414+
input,
415+
&mut new_plugins,
416+
&mut npm_packages_to_remove,
417+
)
418+
.unwrap();
381419

382420
assert_eq!(migrated, expected);
383421

@@ -392,6 +430,7 @@ const appWindow = getCurrentWebviewWindow()
392430
"fs"
393431
]
394432
);
433+
assert_eq!(npm_packages_to_remove, Vec::<String>::new());
395434
}
396435

397436
#[test]
@@ -436,8 +475,15 @@ const appWindow = getCurrentWebviewWindow()
436475
"#;
437476

438477
let mut new_plugins = Vec::new();
478+
let mut npm_packages_to_remove = Vec::new();
439479

440-
let migrated = migrate_imports(Path::new("file.svelte"), input, &mut new_plugins).unwrap();
480+
let migrated = migrate_imports(
481+
Path::new("file.svelte"),
482+
input,
483+
&mut new_plugins,
484+
&mut npm_packages_to_remove,
485+
)
486+
.unwrap();
441487

442488
assert_eq!(migrated, expected);
443489

@@ -452,6 +498,7 @@ const appWindow = getCurrentWebviewWindow()
452498
"fs"
453499
]
454500
);
501+
assert_eq!(npm_packages_to_remove, Vec::<String>::new());
455502
}
456503

457504
#[test]
@@ -466,6 +513,8 @@ import { open } from "@tauri-apps/api/dialog";
466513
import { register } from "@tauri-apps/api/globalShortcut";
467514
import clipboard from "@tauri-apps/api/clipboard";
468515
import * as fs from "@tauri-apps/api/fs";
516+
import { Store } from "tauri-plugin-store-api";
517+
import Database from "tauri-plugin-sql-api";
469518
import "./App.css";
470519
471520
function App() {
@@ -535,6 +584,8 @@ import { open } from "@tauri-apps/plugin-dialog";
535584
import { register } from "@tauri-apps/plugin-global-shortcut";
536585
import clipboard from "@tauri-apps/plugin-clipboard-manager";
537586
import * as fs from "@tauri-apps/plugin-fs";
587+
import { Store } from "@tauri-apps/plugin-store";
588+
import Database from "@tauri-apps/plugin-sql";
538589
import "./App.css";
539590
import * as dialog from "@tauri-apps/plugin-dialog"
540591
import * as cli as superCli from "@tauri-apps/plugin-cli"
@@ -598,8 +649,15 @@ export default App;
598649
"#;
599650

600651
let mut new_plugins = Vec::new();
652+
let mut npm_packages_to_remove = Vec::new();
601653

602-
let migrated = migrate_imports(Path::new("file.js"), input, &mut new_plugins).unwrap();
654+
let migrated = migrate_imports(
655+
Path::new("file.js"),
656+
input,
657+
&mut new_plugins,
658+
&mut npm_packages_to_remove,
659+
)
660+
.unwrap();
603661

604662
assert_eq!(migrated, expected);
605663

@@ -611,8 +669,14 @@ export default App;
611669
"dialog",
612670
"global-shortcut",
613671
"clipboard-manager",
614-
"fs"
672+
"fs",
673+
"store",
674+
"sql"
615675
]
616676
);
677+
assert_eq!(
678+
npm_packages_to_remove,
679+
vec!["tauri-plugin-store-api", "tauri-plugin-sql-api"]
680+
);
617681
}
618682
}

0 commit comments

Comments
 (0)