Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

als-require

Package Overview
Dependencies
Maintainers
0
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

als-require - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

tests/index.html

90

index.js

@@ -1,3 +0,89 @@

const Modules = require('./lib/modules')
const fs = require('fs')
const calledFrom = require('als-called-from')
const { dirname, join } = require('path')
const rootPath = process.cwd()
module.exports = Modules
class Require {
static getModule(path, context) { return new Require(path, context).getContent().build() }
static contents = {}
static relativePath = calledFrom().replace(rootPath, '')
static getFullPath(path,from) {
path = join(dirname(from), path)
if (!path.endsWith('.js')) path += '.js'
return path.replace(/\\/g,'/')
}
constructor(path, context = {}) {
this.modules = {}
this.contents = {}
this.path = path
this.context = context
}
getContent(path = this.path, from = Require.relativePath) {
const getContent =(path) => {
if (this.contents[path] !== undefined) return // allready fetched
if (!Require.contents[path]) {
let content = fs.readFileSync(join(rootPath, path), 'utf-8')
const children = []
content = content.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm, (match, modulePath) => {
if(!modulePath.startsWith('.')) {
console.warn(`The module "${modulePath}" can't be imported and will be replaced with null`)
return match
}
const fullPath = Require.getFullPath(modulePath, path)
if(Require.contents[fullPath] && Require.contents[fullPath].children.includes(path)) {
throw `cyclic dependency between ${path} and ${fullPath}`
}
children.push(fullPath);
return match.replace(modulePath,fullPath)
});
Require.contents[path] = { content, children }
}
const { content, children } = Require.contents[path]
this.contents[path] = content
for (let childPath of children) {
getContent(childPath)
}
}
getContent(Require.getFullPath(path, from))
return this
}
build(modules = this.modules) {
function require(path) {return modules[path] || null}
const keys = Object.keys(this.contents).reverse()
keys.map(path => {
const module = { exports: {} }
const params = { module, require, exports: module.exports, context: this.context }
try { new Function(...Object.keys(params), this.contents[path])(...Object.values(params)) }
catch (error) {this.error(error,path)}
modules[path] = module.exports
})
this.result = modules[keys[keys.length - 1]]
return this
}
error(error,path) {
const stack = []
const pathes = Object.keys(Require.contents).reverse()
function addToStack(curPath) {
stack.push(curPath)
for(const modPath of pathes) {
if(Require.contents[modPath].children.includes(curPath)) {
addToStack(` at ${modPath}`)
break
}
}
}
addToStack(path)
const errorsStack = error.stack.split('\n')
errorsStack.splice(1,1,...stack)
error.stack = errorsStack.join('\n')
throw error
}
}
module.exports = Require

17

package.json
{
"name": "als-require",
"version": "0.3.0",
"description": "A utility for using CommonJS require in the browser and creating bundles.",
"version": "0.4.0",
"main": "index.js",
"scripts": {
"test": "node --test --experimental-test-coverage",
"get-module": "node --test ./tests/get-module.test.js",
"get-module-only": "node --test-only ./tests/get-module.test.js",
"get-module-coverage": "node --test --experimental-test-coverage ./tests/get-module.test.js",
"get-module-report": "node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info ./tests/get-module.test.js",
"modules": "node --test ./tests/modules.test.js",
"modules-only": "node --test-only ./tests/modules.test.js",
"modules-coverage": "node --test --experimental-test-coverage ./tests/modules.test.js",
"modules-report": "node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info ./tests/modules.test.js"
"test": "node --experimental-test-coverage ./tests/index.test.js",
"report":"node --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info ./tests/index.test.js"
},

@@ -27,5 +19,6 @@ "keywords": [

"license": "MIT",
"description": "A utility for using CommonJS require in the browser and creating bundles.",
"dependencies": {
"als-called-from": "^1.0.0"
}
}
}
# als-require
`als-require` is a user-friendly utility designed to facilitate the use of the `require` function in web browsers and to create bundles for CommonJS modules. It simplifies the process of module management in browser environments, allowing for seamless integration and deployment of CommonJS-based code.
`als-require` is a lightweight utility that enables the importation and modification of CommonJS modules before execution in both browser and Node.js environments.
**Capabilities of `als-require`**:
## Features
* Utilize CommonJS modules in the browser, complete with all dependencies and access to module functionalities.
* Employ a unified context object across all modules.
* Modify the code of each module before it is executed.
- **Dynamic Module Loading**: Load JavaScript modules dynamically based on runtime conditions.
- **Cyclic Dependency Detection**: Automatically detects and handles cyclic dependencies within modules.
- **Error Handling**: Provides detailed error information for debugging loading issues.
- **Flexibility**: Supports various module formats and can be easily integrated into different JavaScript environments.
**Where it can be particularly useful:**
* Enables the use of the same codebase on both server and browser, facilitating seamless integration.
* Allows for on-the-fly code rendering without the need for building a separate bundle.
## Installation

@@ -21,74 +25,130 @@

## Usage
## Importing
`als-require` includes two main parts:
1. Browser's script for handling modules
2. Bundle builder for browser
Import in nodejs:
### Dynamic Module Loading in Browsers
```js
const Require = require('als-require')
const module = Require.getModule('./some/path')
```
The browser's script called `getModule`, is a function which fetching all module's chain and then laughing all the chain to get the result.
The fetch is async, that's why `getModule` returns promise.
All module's results, saved in `getModule.modules` object with relative path as a key and module result as a value.
Import in browser:
```html
<script src="/node_modules/als-require/require.js"></script>
<script>
Require.getModule('./some/path')
.then(module => {
// ...
})
</script>
```
**Example:**
## Usage
Let's say, we have moduleA.js which requiring another modules and exporting variable `someExport` and we want to use this module in browser.
Here is the code:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Dynamic Module Loading</title>
</head>
<body>
<script src="node_modules/als-require/require.js"></script>
<script>
getModule('./moduleA.js').then(someExport => {
window.someExport = someExport;
console.log(getModule.modules) // will return object with all modules and their results
});
</script>
</body>
</html>
`als-require` has two files for NodeJS and browser which has same structure and api.
Each file includes `Require` class with folowing structure:
```js
class Require {
static getModule(path, context) {}
static contents = {}
constructor(path, context = {}) {
this.modules = {}
this.contents = {}
this.path = path
this.context = context
}
getContent(path = this.path, from = Require.relativePath) {}
build(modules = this.modules) {}
}
```
In example above, first we include `als-require` script which adding `getModule` function and then, get the module.
The structure above describes only properties and methods for usage, without additional properties and methods which used as private methods.
The constructor gets two arguments: path and context.
* `path` (String): relative path to module for require
* `context` (Object): shared object which will be available in all modules
### Creating and Using Bundles
In this scenario, `als-require` is used to generate a bundle that consolidates all the required modules into a single file. This bundle can then be used in the browser, reducing the number of HTTP requests and streamlining the module loading process.
Here explanation what each method and property used for:
* `Require.getModule` - quick way to get contents and build them in one step
* returns new instance of Requires with ready `contents`, `modules` and `result`
* The method is sync for NodeJS and async for browser
* `Require.contents` - includes modules contents and their children list and used as cache
* `require.getContent()` - used for reading module file's contents
* Adding content to `Require.contents` and to `require.contents`
* The browser version is `async` and NodeJS version is `sync`
* `require.build()` - builds all modules results
* `require.modules` - includes all module's results
* `require.result` - has the main module result (export)
**Example for Generating a Bundle:**
```javascript
const Modules = require('als-require');
const modules = new Modules()
modules.require('./moduleA','moduleAVarname')
modules.require('./moduleB','moduleBVarname')
### Node.Js
modules.scripts // the object with {relativePath:{exports,content}}
```js
const Require = require('als-require')
const path = './relative/path/to/module'
const context = {} // shared object for all modules empty object by default
const mod = new Require(path,context)
mod.getContent() // reading all modules
for(const path in mod.contents) {
mod.contents[path] = mod.contents[path] // modify if needed
}
// Now you can save the script as file
require('fs').writeFileSync('test.js', modules.script);
// Or return it directly
app.get('/bundle.js', (req, res) => {
res.send(modules.script);
});
mod.build() // build the result
mod.result // includes the result of main module
mod.modules // object with all module`s results {relativePath:moduleResult,...}
```
On Browser:
If you want to use node modules libraries, you need to specify relative path.
### Browser
```html
<script src="/bundle.js"></script>
<script src="/node_modules/als-require/require.js"></script>
<script>
console.log(moduleAVarname,moduleBVarname)
console.log(getModule.modules)
const path = './relative/path/to/module'
const context = {} // shared object for all modules empty object by default
const mod = new Require(path,context)
const promise = mod.getContent() // fetching all modules
promise.then(mod => {
for(const path in mod.contents) {
mod.contents[path] = mod.contents[path] // modify if needed
}
mod.build() // build the result
mod.result // includes the result of main module
mod.modules // object with all module`s results {relativePath:moduleResult,...}
})
</script>
```
The bundle is self-sufficient and will include getModule with `getModule.modules` which will include all bundled modules.
## Permitted module path
`Require` class not requiring node_modules packages. All node packages returns null as result.
You can include node module by requiring it's full path. Here is example:
```js
const somePackage = require('some-package');
const somePackage1 = require('./node_modules/some-package/index.js');
module.exports = {somePackage,somePackage1}
```
In case above `somePackage` is `null` but `somePackage1` should be the package.
## Context Usage
The `context` object is a shared space accessible by all modules loaded by `als-require`. This allows modules to read and write shared data, enabling more interactive and dynamic module behaviors.
Make sure you are using the `context` for static value (like constants and common variables and functions) and not dynamic, cause it available to all require's results.
## Error Handling
`als-require` throwing errors in case of cyclic dependencies and if some module throwing error.
For the case of module's error, `Require` adds to stack modules paths which has called.

@@ -1,63 +0,97 @@

async function getModule(path, errors = []) {
const modules = {}
const dependencies = []
async function getContent(path, relative) {
if(!path.startsWith('.')) return // don't include node_modules modules
path = getModule.getFullPath(path, relative)
if(relative !== '') {
if(dependencies.includes(relative+path)) throw `cyclic dependency between ${relative} and ${path}`
else dependencies.push(path+relative)
class Require {
static contents = {}
static async getModule(path, context) {
const mod = new Require(path, context)
await mod.getContent()
return mod.build()
}
static getFullPath(path, relative) {
const pathParts = path.split('/');
const relativeParts = relative.split('/').slice(0, -1);
const fullPathParts = [];
for (let part of [...relativeParts, ...pathParts]) {
if (part === '..') {
if (fullPathParts.length > 0 && fullPathParts[fullPathParts.length - 1] !== '..') fullPathParts.pop();
else fullPathParts.push(part);
} else if (part !== '.') fullPathParts.push(part);
}
if (modules[path] !== undefined) return
const children = []
let response = await fetch(path)
if(!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const content = await response.text()
content.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm, (match, modulePath) => {
children.push(modulePath);
});
modules[path] = content
for (let childPath of children) {
await getContent(childPath, path)
}
let fullPath = fullPathParts.join('/');
return fullPath.endsWith('.js') ? fullPath : fullPath + '.js'
}
if(path) await getContent(path, '')
return getModule.buildModules(modules,errors)
}
getModule.getFullPath = function getFullPath(path, relative) {
let sliceTo = -1
if (path.startsWith('../')) {
path = path.slice(1)
sliceTo = -2
constructor(path, context = {}) {
this.modules = {}
this.contents = {}
this.path = path
this.context = context
}
if (!path.endsWith('.js')) path = path + '.js'
if (relative !== '') {
let dir = relative.split('/').slice(0, sliceTo).join('/')
path = dir + path.replace(/^\.\//, '/')
async getContent(path = this.path, from = location.pathname) {
const getContent = async (path) => {
if (this.contents[path] !== undefined) return // allready fetched
if (!Require.contents[path]) {
let response = await fetch(path)
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
let content = await response.text()
const children = []
content = content.replace(/^(?!\/\/|\/\*.*\*\/).*require\(["'`](.*)["'`]\)/gm, (match, modulePath) => {
if(!modulePath.startsWith('.')) {
console.warn(`The module "${modulePath}" can't be imported and will be replaced with null`)
return match
}
const fullPath = Require.getFullPath(modulePath, path)
if(Require.contents[fullPath] && Require.contents[fullPath].children.includes(path)) {
throw `cyclic dependency between ${path} and ${fullPath}`
}
children.push(fullPath);
return match.replace(modulePath,fullPath)
});
Require.contents[path] = { content, children }
}
const { content, children } = Require.contents[path]
this.contents[path] = content
for (let childPath of children) {
await getContent(childPath)
}
}
await getContent(Require.getFullPath(path, from))
return this
}
return path
}
getModule.buildModules = function buildModules(modules,errors = []) {
let currentModule = '';
function require(path) {
path = getModule.getFullPath(path, currentModule)
return modules[path]
build(modules = this.modules) {
function require(path) {return modules[path] || null}
const keys = Object.keys(this.contents).reverse()
keys.map(path => {
const module = { exports: {} }
const params = { module, require, exports: module.exports, context: this.context }
try { new Function(...Object.keys(params), this.contents[path])(...Object.values(params)) }
catch (error) {this.error(error,path)}
modules[path] = module.exports
})
this.result = modules[keys[keys.length - 1]]
return this
}
const keys = Object.keys(modules).reverse()
keys.forEach(path => {
const module = {}
currentModule = path
try { new Function('module', 'require', modules[path])(module, require) }
catch (error) { errors.push(error) }
if (module.exports) modules[path] = module.exports
else modules[path] = module
getModule.modules[path] = modules[path]
})
const result = modules[keys[keys.length - 1]]
return result
error(error,path) {
const stack = []
const pathes = Object.keys(Require.contents).reverse()
function addToStack(curPath) {
stack.push(curPath)
for(const modPath of pathes) {
if(Require.contents[modPath].children.includes(curPath)) {
addToStack(` at ${modPath}`)
break
}
}
}
addToStack(path)
const errorsStack = error.stack.split('\n')
errorsStack.splice(1,1,...stack)
error.stack = errorsStack.join('\n')
throw error
}
}
getModule.modules = {}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc