DEV Community

Cover image for Adding URL Search Parameters to Imports!
Lioness100
Lioness100

Posted on

Adding URL Search Parameters to Imports!

Here's an interesting bit of knowledge: did you know that you can create and interpret relative file URLs like... actual URLs?

All content covered in this post will only work with ESM

Now, it might be hard to find a practical use for this, but it is undoubtedly very cool 😎. Enough talk; let's look at some code.

// In your first file:
import './example.js?abc=123';
Enter fullscreen mode Exit fullscreen mode
// In your second file, example.js:
const url = new URL(import.meta.url);
const searchParam = url.searchParams.get('abc');

console.log(searchParam); // → '123'
Enter fullscreen mode Exit fullscreen mode

Here, import.meta.url is used to display the full URL used to import the module. In this case, for example, it might be:

file:///C:/Some/Folder/Path/example.js?abc=123
Enter fullscreen mode Exit fullscreen mode

From here, we can create an instance of a URL, which will make it super easy to parse search parameters.

How could this be used?

I have no idea 😂! Maybe it could be used as a shortcut for very primitive module configuration? For example, using the very popular utility package dotenv.

GitHub logo motdotla / dotenv

Loads environment variables from .env for nodejs projects.

Works with dotenv-vault. Learn more at dotenv.org.

dotenv

dotenv

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology.

BuildStatus Build status NPM version js-standard-style Coverage Status LICENSE Conventional Commits Rate on Openbase

Install

# install locally (recommended)
npm install dotenv --save
Enter fullscreen mode Exit fullscreen mode

Or installing with yarn? yarn add dotenv

Usage

Create a .env file in the root of your project:

S3_BUCKET="YOURS3BUCKET"
SECRET_KEY="YOURSECRETKEYGOESHERE"
Enter fullscreen mode Exit fullscreen mode

As early as possible in your application, import and configure dotenv:

require('dotenv').config()
console.log(process.env) // remove this after you've confirmed it working
Enter fullscreen mode Exit fullscreen mode

.. or using ES6?

import 'dotenv/config' // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import
import express from 'express'
Enter fullscreen mode Exit fullscreen mode

That's it. process.env now has the keys and values you defined in your .env file:

require('dotenv').config()
.
Enter fullscreen mode Exit fullscreen mode

Instead of:

import dotenv from 'dotenv';
dotenv.config({ debug: true });
Enter fullscreen mode Exit fullscreen mode

You could do this! 🦄

import 'dotenv/config?debug=true';
Enter fullscreen mode Exit fullscreen mode

I'd love to know your thoughts 😆

Discussion (2)

Collapse
prantlf profile image
Ferdinand Prantl • Edited on

I use it in my test harness to create a named test suite by a single import line. Instead of the usual importing index.min.mjs and calling the test suite factory:

import tehanu from './node_modules/tehanu/dist/index.min.mjs'

const test = tehanu('sum')
Enter fullscreen mode Exit fullscreen mode

I can import suite.min.mjs which recognises the URL parameter name, creates a test suite with the name and exports it:

import test from './node_modules/tehanu/dist/suite.min.mjs?name=sum'
Enter fullscreen mode Exit fullscreen mode

It's a pity that this works only in browsers. Node.js doesn't separate the URL parameters from the file path, which leads to an invalid script path, if they are attached:

❯ node 'lib/index.mjs'
no suites

❯ node 'lib/index.mjs?test'
node:internal/modules/cjs/loader:936
  throw err;
  ^
Error: Cannot find module '/.../tehanu/packages/teru/lib/index.mjs?test'
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}
Enter fullscreen mode Exit fullscreen mode

This has probably a consequence that the URL parameters can't be used in subpackages either. If a library exposes a subpackage suite, for example:

{
  "exports": {
    ".": {
      "require": "./lib/index.cjs",
      "import": "./lib/index.mjs"
    },
    "./suite": "./lib/suite.mjs"
  }
}
Enter fullscreen mode Exit fullscreen mode

it has to be used as-is:

import test from 'tehanu/suite'
Enter fullscreen mode Exit fullscreen mode

instead of the desired:

import test from 'tehanu/suite?name=sum'
Enter fullscreen mode Exit fullscreen mode

which fails:

❯ node lib/index.mjs test/index.mjs
node:internal/errors:465
    ErrorCaptureStackTrace(err);
    ^
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './suite?name=sum' is not defined by "exports" in /.../tehanu/packages/teru/node_modules/tehanu/package.json imported from /.../tehanu/packages/teru/test/index.mjs
    at new NodeError (node:internal/errors:372:5)
    at throwExportsNotFound (node:internal/modules/esm/resolve:472:9)
    at packageExportsResolve (node:internal/modules/esm/resolve:753:3)
    at packageResolve (node:internal/modules/esm/resolve:935:14)
    at moduleResolve (node:internal/modules/esm/resolve:1003:20)
    at defaultResolve (node:internal/modules/esm/resolve:1218:11)
    at ESMLoader.resolve (node:internal/modules/esm/loader:580:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:294:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:80:40)
    at link (node:internal/modules/esm/module_job:78:36) {
  code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
}
Enter fullscreen mode Exit fullscreen mode

Related:

Collapse
lioness100 profile image
Lioness100 Author

WOW! I never thought of that use case, and your findings are really interesting! Thank you so much!! ♥️♥️