Create a Node package on your local Laravel environment
Tags: javascript, node, laravel, tutorial
Published: 2024-03-19 10:13:18

TL;DR: How to set up a local development environment to test your Node package classes or utilities in a local Laravel project.

&nbsp;
&nbsp;

You will find a link to a [CodeSandbox Demo](https://codesandbox.io/p/devbox/github/capsulescodes/articles/tree/013-create-a-node-package-on-your-local-laravel-environment) or the source code via this [Github Repository](https://github.com/capsulescodes/articles/tree/013-create-a-node-package-on-your-local-laravel-environment). Learn more on [Capsules](https://capsules.codes/en/blog) or [X](https://x.com/capsulescodes).

&nbsp;
&nbsp;

It still shouldn't come as a surprise that we use hundreds of packages when developing web tools. To get them, you just need to shop around with a package manager like NPM, which had 2 633 573 packages as of January 2024.

&nbsp;
&nbsp;

If you're looking to develop your own package, it's completely legitimate to wonder how to test it under real conditions. Publishing the package on NPM during development isn't a good option. Another approach would be to integrate it into a blank project without using NPM. The method in this article is much closer to a real-world scenario but requires environment preparation.

&nbsp;
&nbsp;

Create a folder that will serve as the foundation for your package.

&nbsp;
&nbsp;

```bash
mkdir package
```

&nbsp;
&nbsp;

Create a `package.json` file, which serves as the essential foundation of the package.

&nbsp;
&nbsp;

`package/package.json`


```json
{
    "name": "capsulescodes-package",
    "description": "Capsules Codes Package",
    "type": "module",
}
```
- `name` :The name should be structured with the entity on the left and the package name on the right. It's strongly recommended to use a descriptive package name to make it easier for users to search.
- `description` : The package description should be clear and concise.
- `type` : Specifying `module` as the type allows loading JavaScript files as ES modules instead of CommonJS modules.

&nbsp;
&nbsp;

Additionally, running `npm init` in a folder that doesn't contain a `package.json` file will launch a wizard that guides you through the process of creating your `package.json` file.

&nbsp;
&nbsp;

Create a folder `src` inside the package folder.

&nbsp;
&nbsp;

```bash
cd package 
mkdir src
```
- The arrangement of folders doesn't have much real significance, apart from their proximity, both for you and for this article.

&nbsp;
&nbsp;

Create a JavaScript class named `Greeter` containing a function greet that returns the phrase `Hello world!` .

&nbsp;
&nbsp;

`package/src/Greeter.js`

```javascript
export default class Greeter
{
    static greet()
    {
        return 'Hello world!';
    }
}
```

&nbsp;
&nbsp;

Then, you need to specify which file the package should refer to, in this case, `src/Greeter.js` by default.

&nbsp;
&nbsp;

`package/package.json`

```json
{
    ...
    "main" : "src/Greeter.js"
    ...
}
```

&nbsp;
&nbsp;

Now, it's possible to test this package. To do so, you need to create a testing environment using a Laravel project template.

&nbsp;
&nbsp;

Return to the parent directory of the `package` and create a Laravel project to serve as a testing template. A Laravel Vue Inertia Tailwind project is used as a `template` for this article.

&nbsp;
&nbsp;

```bash
cd ..
mkdir template
cd template
```

&nbsp;
&nbsp;

The package is ready to be installed.

&nbsp;
&nbsp;

Run the command `npm install ../package` at the root of the `template` project or specify the new local dependency in the `package.json` file.

&nbsp;
&nbsp;

`template/package.json`

```json
{
    "dependencies": {
        "capsulescodes-package" : "file:../package"
    }
}
```
- The annotation `file:` indicates that it's a path to a local folder. Changes made in the `package` folder will take effect in the `node_modules` folder of the `template` folder.
- `npm uninstall capsulescodes-package` allows you to uninstall the local package.

&nbsp;
&nbsp;

Testing it via the terminal :

&nbsp;
&nbsp;

```bash
> node -e "import( 'capsulescodes-package' ).then( module => console.log( module.default.greet() ) );"

Hello world!
```

&nbsp;
&nbsp;

It is not common to run code directly via node, but `-e` or `--eval` allows you to evaluate the given argument.

&nbsp;
&nbsp;

or modifying the `Welcome.vue` file to test the static `Greeter` class :

&nbsp;
&nbsp;

`template/resources/js/pages/Welcome.vue`

```vue
<script setup>

import Greeter from 'capsulescodes-package';

import logotype from '/public/assets/capsules-logotype.svg';

</script>

<template>

    <div class="w-screen h-screen flex flex-col items-center justify-center text-center">

        <img class="w-24 h-24" v-bind:src="logotype" v-bind:alt="'Capsules Codes Logotype'">

        <h1 class="mt-4 text-6xl font-bold select-none header-mode" v-text="Greeter.greet()" />

    </div>

</template>
```

&nbsp;
&nbsp;

![Capsules Node Package Image 1](https://capsules.codes/storage/canvas/images/BVpEYOYiBJbLcDHSHzPkciynfIcgfd0adWim64BV.png)

&nbsp;
&nbsp;

The working environment is set up.

&nbsp;
&nbsp;

It would be interesting to add the additional method `say()` that takes a `string` as a parameter to test the tool in real time.

&nbsp;
&nbsp;

`package/src/Greeter.js`

```javascript
export default class Greeter
{
		...

    static say( something )
    {
        return something;
    }
}
```

&nbsp;
&nbsp;

Testing it via the terminal :

&nbsp;
&nbsp;

```bash
> node -e "import( 'capsulescodes-package' ).then( module => console.log( module.default.say( 'That\'s a quick way to develop and test a package!' ) ) );"

That's a quick way to develop and test a package!
```

&nbsp;
&nbsp;

or modifying the `Welcome.vue` file to test the static `Greeter` class :

&nbsp;
&nbsp;

`template/resources/js/pages/Welcome.vue`

```vue
<script setup>

import logotype from '/public/assets/capsules-logotype.svg';

import Greeter from 'capsulescodes-package';

</script>

<template>

    <div class="w-screen h-screen flex flex-col items-center justify-center text-center">

        <img class="w-24 h-24" v-bind:src="logotype" v-bind:alt="'Capsules Codes Logotype'">

        <h1 class="mt-4 text-6xl font-bold select-none header-mode" v-text="Greeter.greet()" />

        <h2 class="mt-4 text-xl font-bold select-none header-mode" v-text="Greeter.say( 'That\'s a quick way to develop and test a package!' )" />

    </div>

</template>
```

&nbsp;
&nbsp;

![Capsules Node Package Image 2](https://capsules.codes/storage/canvas/images/3WJGcmx3s48FGJKgDJos5QxbwkSBrM5p3zueEgqo.png)

&nbsp;
&nbsp;

At this stage, everything is ready to develop a simple Node package. However, in this article, the focus is on implementing a `npm run greet` command that will call the static `Greeter` class.

&nbsp;
&nbsp;

It's necessary to create the `greet` command at first. To do this, return to the `package` folder and create the `Greet.js` command in the `Commands` folder of the source directory `src`.

&nbsp;
&nbsp;

`package/src/Commands/Greet.js`

```javscript
#!/usr/bin/env node

import Greeter from '../Greeter.js';

console.log( Greeter.greet() );
```
- `#!/usr/bin/env node` indicate that it is a node executable.

&nbsp;
&nbsp;

To access this command in the `template` you can then run either :

&nbsp;
&nbsp;

```bash
node node_modules/capsulescodes-package/src/commands/greet.js
```

&nbsp;
&nbsp;

Or add a script in the `package.json` file that will achieve the same result :

&nbsp;
&nbsp;

`template/package.json`

```json
"scripts": {
    ...
    "greet": "node node_modules/capsulescodes-package/src/commands/greet.js"
},
```

&nbsp;
&nbsp;

```bash
> npm run greet

> greet
> node node_modules/capsulescodes-package/src/commands/greet.js

Hello world!
```

&nbsp;
&nbsp;

All that’s left is to create the binary via `package.json`.

&nbsp;
&nbsp;

`package/package.json`

```json
"bin": {
    "greet" : "src/Commands/Greet.js"
}
```

&nbsp;
&nbsp;

This property, upon installing the package, will copy the specified file `src/Commands/Greet.js` and paste it into the `node_modules/.bin/` folder, renaming this file with the given key `greet`.

&nbsp;
&nbsp;

If, as in our case, our package is already installed, running yet another `npm install ../package` will restart the process.

&nbsp;
&nbsp;

You just need to add a new script to the `package.json` file or simply run the command `npx greet` [ where `npx greet` is equivalent to `node node_modules/.bin/greet` ].

&nbsp;
&nbsp;

`template/package.json`

```json
"scripts": {
    "greet": "greet"
},
```

```bash
> npm run greet

> greet
> greet

Hello world!
```

```bash
> npx greet

Hello world!
```

&nbsp;
&nbsp;

For the case of the static method `say` and its parameter, a new command is needed.

&nbsp;
&nbsp;

`package/src/Commands/Say.js`

```javascript
#!/usr/bin/env node

import Greeter from '../Greeter.js';

console.log( Greeter.say( process.argv[ 2 ] ) );
```
- `process.argv` represents the arguments of the command, where `process.argv[0]` contains `node` and `process.argv[1]` contains the `node_modules/.bin/say` binary in this case.

&nbsp;
&nbsp;

The command can be added to the list of binaries in the `package.json` file.

&nbsp;
&nbsp;

`package/package.json`

```json
"bin": {
    "say" : "src/Commands/Say.js"
}
```

&nbsp;
&nbsp;

You just need to add a new script to the `package.json` file or simply run the command `npx say "Capsules Codes"`.

&nbsp;
&nbsp;

template/package.json

```json
"scripts": {
    ...
    "say": "say"
},
```

```bash
> npm run say "Capsules Codes"

> say
> say Capsules Codes

Capsules Codes
```

```bash
> npx say "Capsules Codes"

Capsules Codes
```

&nbsp;
&nbsp;

You want to publish this amazing package? One last small step is necessary: avoid publishing all the files in the project :

&nbsp;
&nbsp;

`package/package.json`

```json
"files": [ "!*", "src" ]
```
- `!*` indicates that it should exclude everything. Therefore, only the `src` folder will remain to be kept.

&nbsp;
&nbsp;

```bash
npm publish
```
- This command requires being logged in to NPM via `npm login`.
It's necessary to specify the `version` in the `package.json` file when publishing.

&nbsp;
&nbsp;

Glad this helped.