Swapping Out Imports with Window Objects in TypeScript

After creating a TypeScript module that relies on a third-party library, the JavaScript output from compilation includes a statement using require:

"use strict";
var dexie_1 = require("dexie");
var storage;
(function (storage) {
  ...
})(storage || (storage = {}));

While this works fine for Node.js environments, I would like to replace var dexie_1 = require("dexie"); with var dexie_1 = window.Dexie; for use in a browser.

Is it possible to swap out the require statement in the compiled JS with an object from the global namespace (window)? Are there any Gulp plugins or similar tools available for this task?

Here's a snippet of my tsconfig.json:

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "target": "es5"
  },
  "exclude": [
    "node_modules",
    "typings/browser",
    "typings/browser.d.ts"
  ]
}

Answer №1

Is it possible to replace imports with window objects?

Unfortunately, replacing imports with window objects is not feasible. However, there are two alternative solutions:

Option 1: Use global objects

When an object is loaded in the browser using a script tag, it becomes a global variable in your code. In TypeScript, you can utilize a global declaration file for this purpose. Since modules are not utilized in this scenario, there is no need for import statements.

Option 2: Use a bundler or a loader

To address the issue of replacing imports with window objects, consider utilizing a bundler such as Webpack. Alternatively, you could also opt for a loader like SystemJS.

Answer №2

Webpack has the capability to map require("dexie"); to window.Dexie.

To achieve this, simply add the following configuration in your webpack.config.js:

module.exports = {
  externals: {
    'dexie': 'Dexie'
  }
};

Below is a detailed example for better understanding:

Directory Structure:

  • bower_components (directory created from bower install)
  • dist (directory generated by gulp default)
  • node_modules (directory obtained through npm install)
  • src (folder containing TypeScript source code)
  • typings (folder created using typings install)
  • bower.json (Frontend dependencies file)
  • gulpfile.js (Build configuration file)
  • index.html (demo page to test webpacked code)
  • index.js (main entry point for distribution)
  • package.json (workflow and build dependencies file)
  • tsconfig.json (TypeScript compiler configuration file)
  • webpack.config.json (Webpack configuration file)

src/storage.ts

/// <reference path="../typings/index.d.ts" />
import Dexie from "dexie";

namespace storage {
  export function setupDatabase():void {
    let db = new Dexie('MyDatabase');

    db.version(1).stores({
      friends: 'name, age'
    });

    db.open().then(function () {
      console.log('Initialized database: ' + db.name);
    });
  }
}

module.exports = storage;

bower.json

{
  "name": "storage",
  "main": "dist/webpacked.js",
  "private": true,
  "dependencies": {
    "dexie": "^1.4.1"
  }
}

gulpfile.js

var gulp = require('gulp');
var rename = require('gulp-rename');
var runSequence = require('run-sequence');
var ts = require('gulp-typescript');
var tsProject = ts.createProject('tsconfig.json');
var webpack = require('webpack-stream');

gulp.task('build', function () {
  return gulp.src('src/**/*.ts')
    .pipe(ts(tsProject))
    .pipe(gulp.dest('dist'));
});

gulp.task('webpack', function () {
  return gulp.src('dist/index.js')
    .pipe(webpack(require('./webpack.config.js')))
    .pipe(rename('webpacked.js'))
    .pipe(gulp.dest('dist'));
});

gulp.task('default', function (done) {
  runSequence('build', 'webpack', done);
});

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Demo</title>
    <script src="bower_components/dexie/dist/dexie.js"></script>
    <script src="dist/webpacked.js"></script>
  </head>
  <body>
    <script>
      document.addEventListener("DOMContentLoaded", function() {
        storage.setupDatabase();
      }, false);
    </script>
  </body>
</html>

index.js

window.storage = require('./dist/storage');

package.json

{
  "name": "storage",
  "private": true,
  "devDependencies": {
    "dexie": "^1.4.1",
    "gulp": "^3.9.1",
    "gulp-rename": "^1.2.2",
    "gulp-typescript": "^2.13.6",
    "run-sequence": "^1.2.2",
    "webpack-stream": "^3.2.0"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "target": "es5"
  },
  "exclude": [
    "node_modules",
    "typings/browser",
    "typings/browser.d.ts"
  ]
}

typings.json

{
  "globalDependencies": {
    "node": "registry:dt/node#6.0.0+20160709114037"
  }
}

In conclusion, by setting up the configurations as mentioned above, you can successfully bundle and use your TypeScript code with Webpack while ensuring all dependencies are correctly referenced.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adjusting ngClass dynamically as values change

Currently, I am facing a situation where I want to dynamically add a class to my view using ngClass based on changes in the output value. The output value is dependent on the response received from an API, and I am fetching data from the endpoint every sec ...

Creating a model for a different user involves several steps that can be easily

Recently, I have been working on a project involving user interactions such as following other users and viewing their content. Using technologies like Prisma, GraphQL, and Nexus, I decided to create a following model today. The model structure is as follo ...

Removing a portion of an item with the power of RxJS

I possess the subsequent entity: const myObject = { items:[ { name: 'John', age: 35, children: [ { child: 'Eric', age: 10, sex: 'M' }, { ...

Converting JSON data into TypeScript interface objects within an Angular 2 environment

I have a JSON dataset with the following structure: { "timestamp": 1467471622, "base": "USD", "rates": { "AED": 3.673027, "AFN": 68.475, "ALL": 123.095199, "AMD": 476.8075, "ANG": 1.78385, "AOA": 165.846832, "ARS": 15.05 ...

Is Angular 9's default support for optional chaining in Internet Explorer possible without the need for polyfill (core-js) modifications with Typescript 3.8.3?

We are in the process of upgrading our system to angular 9.1.1, which now includes Typescript 3.8.3. The @angular-devkit/[email protected] utilizing [email protected]. We are interested in implementing the optional chaining feature in Typescript ...

Issues encountered when attempting to use @rollup/plugin-json in conjunction with typescript

I have been encountering an issue with my appsettings.json file. Despite it being validated by jsonlint.com, and having the tsconfig resolveJsonModule option set to true, I am facing difficulties while importing @rollup/plugin-json. I have experimented wit ...

The type 'GetServerSidePropsContext<ParsedUrlQuery, PreviewData>' does not include property X

My current setup includes: type Session = { bearer: string, firstName: string, lastName: string, etc... }; interface ServerContext extends GetServerSidePropsContext { session: Session, }; export type ServerProps<P extends { [key: string]: ...

Directing non-www to www in Next.js has never been easier

Based on the information I've gathered, it seems that using www is more effective than not using it. I am interested in redirecting all non-www requests to www. I am considering adding this functionality either in the next.config.js file or, if that& ...

Revamp the button's visual presentation when it is in an active state

Currently, I'm facing a challenge with altering the visual appearance of a button. Specifically, I want to make it resemble an arrow protruding from it, indicating that it is the active button. The button in question is enclosed within a card componen ...

Error in NextJS: Attempting to access a length property of null

Does anyone have insights into the root cause of this error? warn - Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works TypeError: Cannot read properties of null (reading 'lengt ...

Intercepting HTTP requests in Angular, but not making any changes to the

Working on Angular 13, I am trying to attach a JWT token to the headers in order to access a restricted route on the backend. However, after inspecting the backend, it seems that the JwtInterceptor is not modifying the HTTP request headers. I have included ...

How can I ensure I am receiving real-time updates from a Resolver Service by subscribing and staying in sync with the

How can I effectively implement this code without encountering an error? "Property 'resolve' in type 'DocumentaryResolverService' is not assignable to the same property in base type 'Resolve'." import { Documentary } from ...

Tips for utilizing a personalized design with the sort-imports add-on in VS Code?

After recently installing the VS Code extension sort-imports, I decided to give a custom style called import-sort-style-module-alias a try. Following what seemed to be the installation instructions (via npm i import-sort-style-module-alias) and updating m ...

Converting a string date format to UTC: A step-by-step guide

In my Typescript code, I am trying to convert a date/time format from string to UTC format but currently facing an issue with it. The desired output is as follows: 2018/10/27+16:00 => 20181027T01000Z import * as moment from 'moment' dates=$ ...

What is the best approach to validating GraphQL query variables while utilizing Mock Service Worker?

When simulating a graphql query with a mock service worker (MSW), we need to verify that the variables passed to the query contain specific values. This involves more than just type validation using typescript typings. In our setup, we utilize jest along ...

Exploring the differences in object shapes using TypeScript

I'm currently working on defining an object that has the ability to hold either data or an error. export type ResultContainer = { data: any; } | { error: any; }; function exampleFunction():ResultContainer { return { data: 3 } } ...

Whenever I attempt to render a component passed as a prop, I encounter error TS2604

I am attempting to pass a component as a prop to another component in order to wrap the content of a material ui modal This is my attempt so far: import React, { Component } from 'react'; import withWidth, { isWidthDown } from '@material-u ...

Typing Redux Thunk with middleware in TypeScript: A comprehensive guide

I recently integrated Redux into my SPFx webpart (using TypeScript), and everything seems to be working fine. However, I'm struggling with typing the thunk functions and could use some guidance on how to properly type them. Here's an example of ...

What is the best way to revert a screen's state back to its original state while utilizing react navigation?

How can I reset the state in a functional component back to its initial state when navigating using navigation.navigate()? For example, if a user navigates to screen A, sets some state, then clicks a button and navigates to screen B, and then goes back to ...

Using Generic Types in TypeScript Files for React Components

I have encountered an issue that I haven't been able to find a solution for online. When I define a function in a ts file like this: const lastGeneric = <T>(arr: Array<T>): T => { return arr[arr.length - 1]; } But when I try to do ...