UNPKG

@servicenow/sdk

Version:
194 lines (142 loc) 8.39 kB
--- tags: [module, server module, import, export, glide API, third-party library, code reuse, servicenow glide, quickstart, modular javascript, modern] --- # JavaScript Modules JavaScript modules are the **modern, preferred approach** for all server-side code in Fluent projects. Modules support `import`/`export`, provide access to typed Glide APIs via `@servicenow/glide`, enable code reuse across your application, and integrate with third-party npm libraries. ## When to Use Use modules for server-side scripts in APIs that accept function types. Not all APIs support modules — some `script` properties only accept strings. If the compiler or build rejects a module import (for example, a type error such as `Type '() => void' is not assignable to type 'string'`, or a similar diagnostic), the API does not support modules and you should use `Now.include()` instead (see the `now-include-guide` topic). The exact error will vary depending on the structure of your module export and the API you're targeting. **APIs that support modules (accept functions):** - BusinessRule, ScriptAction, UiAction — `script` property - RestApi route handlers — `script` property - CatalogItemRecordProducer — `script` and `postInsertScript` properties - ScheduledScript — `script` property **APIs that require Now.include() or inline strings:** - ScriptInclude, ClientScript — `script` is string-only - CatalogClientScript, CatalogUiPolicy, UiPolicy — script fields are string-only - SPWidget — all script fields are string-only - Record API — data values are strings ### Additional use cases - Organizing reusable server-side code into importable files - Importing Glide APIs (`gs`, `GlideRecord`, etc.) for use in module files - Adding third-party npm libraries to an application ## Instructions 1. **Module file location in src** Module files must be placed in the `serverModules` directory defined in `now.config.json`, which defaults to `src/server` 2. **Import Glide APIs explicitly:** In module files, `gs`, `GlideRecord`, and other Glide APIs are NOT automatically available. You must import them from `@servicenow/glide`. Analyze your script for ALL ServiceNow APIs used and import each one. 3. **Exception -- Script Include classes:** When writing Script Include class files (`Class.create` pattern), do NOT import Glide APIs. They are automatically available in Script Include execution context. Only import other Script Include classes from `@servicenow/glide/<scopeName>`. 4. **Use `export`/`import` in modules, `require` in scripts:** Modules use ES module syntax (`export`/`import`). Business rules, script includes, and other server scripts use `require` to consume module exports. 5. **Declare dependencies in package.json:** Third-party npm libraries must be declared in `dependencies`. Never modify versions of existing dependencies unless explicitly requested. 6. **Verify Glide API methods exist:** Only use methods explicitly defined in `@servicenow/glide` type definitions. Do not assume methods exist based on naming conventions. 7. **Use `GlideDateTime` instead of `gs.nowDateTime()`** -- `gs.nowDateTime()` is not allowed in scoped applications. 8. **Use Typescript** for creating module code unless instructed to use Javascript explicitly ## Key Concepts ### Import Patterns - **Glide APIs in modules:** `import { gs, GlideRecord } from '@servicenow/glide'` - **Namespaced APIs:** `import { RESTAPIRequest } from '@servicenow/glide/sn_ws_int'` - **Script Include classes:** `import { MyClass } from '@servicenow/glide/x_my_scope'` - **Module code in scripts:** `const { myFunction } = require('path/to/module')` ### Script Include Module Rules This is the most common source of errors: - **Module files with normal functions** -- MUST import Glide APIs from `@servicenow/glide` - **Module files with Script Include classes (`Class.create`)** -- must NOT import Glide APIs (they are auto-available) - **Consuming Script Include classes from other modules** -- import from `@servicenow/glide/<scopeName>` ### Exposing Modules Through Script Includes Many platform features still require script includes — GlideAjax, cross-scope APIs, and extension points that call script includes by name. When your logic lives in a module but needs to be accessible through these mechanisms, create a script include that acts as a thin bridge using `require()`. See the "Bridging Modules Through Script Includes" section in the `script-include-guide` topic for the full pattern and examples. ### Subpath Imports Use subpaths in `package.json` to create shorthand imports: ```json { "imports": { "#calc": "calculus", "#derivative": "calculus/derivative" }, "dependencies": { "calculus": "1.0.0" } } ``` Then use the shorthand: ```typescript fluent import { derivative } from '#derivative' import * as calculus from '#calc' ``` ### Limitations - Modules work only within the application scope -- no cross-scope module sharing - Node.js APIs are not supported - Third-party libraries cannot access ServiceNow APIs such as GlideRecord and other imports from `@servicenow/glide` - CommonJS modules from third-party libs are not supported unless they define exports - Only a subset of ECMAScript features are supported ## Avoidance - **Never use Glide APIs without importing them in module files** -- they are NOT globally available in module context - **Never import Glide APIs in Script Include class files** -- they ARE globally available in that context - **Never reference Script Include classes via global scope prefix in modules** -- `new x_myapp.MyUtils()` only works in non-module server scripts. In modules, it throws a runtime error (`x_myapp is not defined`). Always use `import { MyUtils } from '@servicenow/glide/x_myapp'` instead. - **Never use methods not in `@servicenow/glide` type definitions** -- ServiceNow's Glide objects have specific, limited APIs - **Never modify existing dependency versions in package.json** -- only add new dependencies - **Never use `gs.nowDateTime()` in scoped apps** -- use `new GlideDateTime().getDisplayValue()` instead ## Examples ### Full Pattern: Business Rule with Module This is the recommended pattern for server-side scripts. Write the logic in a module file and import it in the `.now.ts` definition: **Fluent definition** (`src/fluent/business-rules/validate-request.now.ts`): ```typescript fluent import '@servicenow/sdk/global' import { BusinessRule } from '@servicenow/sdk/core' import { validateRequest } from '../../server/business-rules/validate-request' BusinessRule({ $id: Now.ID['validate-request'], name: 'Validate Request', table: 'x_myapp_request', when: 'before', action: ['insert', 'update'], script: validateRequest, }) ``` **Module file** (`src/server/business-rules/validate-request.ts`): ```typescript fluent import { gs, GlideRecord } from '@servicenow/glide' export function validateRequest(current: GlideRecord<'x_myapp_request'>, previous: GlideRecord<'x_myapp_request'>) { var title = current.getValue('short_description'); if (!title) { gs.addErrorMessage('Short description is required'); current.setAbortAction(true); } } ``` ### Exporting from a Module ```typescript fluent function myFunction() {} const myVariable = 'value' // Named exports for multiple features export { myFunction, myVariable } ``` ### Importing in Another Module ```typescript fluent import { feature } from 'path/to/module' ``` ### Importing in a Server Script (Business Rule, etc.) ```typescript fluent const { feature } = require('path/to/module') ``` ### Importing Glide APIs in a Module ```typescript fluent import { gs } from '@servicenow/glide' import { GlideRecord } from '@servicenow/glide' // Namespaced APIs import { RESTAPIRequest, RESTAPIResponse } from '@servicenow/glide/sn_ws_int' ``` ### Using Script Include Classes from Modules ```typescript fluent import { RecordUtils } from '@servicenow/glide/x_my_scope' export function onRecordInsert(current, previous) { var recordUtils = new RecordUtils() } ``` ### Adding Dependencies in package.json ```json { "name": "test", "version": "1.0.0", "dependencies": { "math": "1.0.0" } } ``` When adding new dependencies, NEVER modify the versions of existing dependencies. Only add the new entry.