Using Alpine's Persist plugin in a separate JavaScript file
Tags: alpinejs, javascript
Published: 2022-02-09 20:34:14

---
title: Using Alpine's Persist plugin in a separate JavaScript file
published: true
description: How to use Alpine's $persist when defining x-data as a function in a separate JavaScript file.
tags: alpinejs, javascript
//cover_image: https://direct_url_to_image.jpg
---

Alpine's Persist plugin stores the value of an Alpine variable in local storage, which allows it to persist across page navigations and still be present on subsequent visits to the site. It is accessed through the magic `$persist` function.

```html
<div x-data="{greeting: $persist('hello world')}">
  <input type="text" x-model:value="greeting" />
</div>
```

## The problem

When a page or component has lots of functionality, Alpine's `x-data` attribute can get a little unwieldy. 

Thankfully you can extract the x-init data into a function. Unfortunately, the following won't work:

```js
// app.js

function myData() {
  return {
    greeting: $persist("hello world")
  };
}
```

```html
<!-- app.js imported above. -->

<div x-data="myData()">
  <h1 x-text="greeting"></h1> 
</div>
```

The `app.js` script file doesn't have access to the magic `$persist` function. Using `this.$persist` won't work either.

## The solution

Fortunately, it's simple to use Alpine's Persist plugin when defining `x-data` as a function in a script file. All you need to do is replace `$persist` with `Alpine.$persist`:

```js
// app.js

function myData() {
  return {
    greeting: Alpine.$persist("hello world")
  };
}
```

With this change, you will be able to use the persist function in a separate script file. This works because under the hood, the persist plugin just binds itself to the Alpine object ([source code](https://github.com/alpinejs/alpine/blob/main/packages/persist/src/index.js)). 

## Gotchas

There are two gotchas you can run into when trying to get this all to work.

### Gotcha 1: The x-data function must be globally accessible.

If you use Webpack, Vite or nearly any other bundler, the functions you define in your JavaScript files won't be globally accessible. You can test this by trying to call the function directly in the JavaScript console within the browser's developer tools. If you run `myData()` in the console and get an error that says `Uncaught ReferenceError: myData is not defined`, it means that Alpine can't see the `myData()` function either.

To fix this, assign the `myData` function to the `window` object:

```js
// app.js

function myData() {
  return {
    greeting: Alpine.$persist("hello world")
  };
}

window.myData = myData;
```

`window` is the global scope in JavaScript, which means `myData()` will now be accessible anywhere.

### Gotcha 2: The x-data function must be defined before Alpine initializes

In Alpine.js, the order in which scripts load matters. You must make sure that the script where your `x-data` function is defined loads before Alpine.

If you're loading Alpine through CDN script tags, you can ensure that the `x-data` function is defined before Alpine initializes by including the script where it is defined before the Alpine scripts:

```html
<!DOCTYPE html>
<html>
  <head>
    <!-- Our script comes first -->
    <script defer src="app.js"></script>
    <script defer src="https://unpkg.com/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>
    <script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
  </head>
  <body>
    <div x-data="myData()">
      <input type="text" x-model:value="greeting" />
    </div>
  </body>
</html>
```

If you're using Alpine as an NPM package, you need to make sure that you define your x-data function _before_ you call `Alpine.start()`:

```js
import Alpine from "alpinejs";
import persist from "@alpinejs/persist";

/** Our function comes before Alpine.start() */
function myData() {
  return {
    greeting: Alpine.$persist("hello world")
  };
}

window.myData = myData;

window.Alpine = Alpine;
Alpine.plugin(persist);
Alpine.start();
```