Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Dual-Support ESM & CJS #662

Merged
merged 11 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 8 additions & 13 deletions .jsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,13 @@ module.exports = {
template: './node_modules/jsdoc-fresh',
recurse: true,
verbose: true,
destination: './docs/'
destination: './docs/',
},
plugins: [
'plugins/markdown',
'jsdoc-region-tag'
],
plugins: ['plugins/markdown', 'jsdoc-region-tag'],
source: {
excludePattern: '(^|\\/|\\\\)[._]',
include: [
'build/src',
],
includePattern: '\\.js$'
include: ['build/esm/src/'],
includePattern: '\\.js$',
},
templates: {
copyright: 'Copyright 2019 Google, LLC.',
Expand All @@ -42,10 +37,10 @@ module.exports = {
systemName: 'gaxios',
theme: 'lumen',
default: {
outputSourceFiles: false
}
outputSourceFiles: false,
},
},
markdown: {
idInHeadings: true
}
idInHeadings: true,
},
};
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,25 @@ $ npm install gaxios
## Example

```js
const {request} = require('gaxios');
const res = await request('https://www.googleapis.com/discovery/v1/apis/');
import {request} from 'gaxios';
const res = await request({url: 'https://google.com/'});
```

## Setting Defaults

Gaxios supports setting default properties both on the default instance, and on additional instances. This is often useful when making many requests to the same domain with the same base settings. For example:

```js
const gaxios = require('gaxios');
gaxios.instance.defaults = {
import {request, instance} from 'gaxios';

instance.defaults = {
baseURL: 'https://example.com'
headers: new Headers({
Authorization: 'SOME_TOKEN'
})
}
gaxios.request({url: '/data'}).then(...);

await request({url: '/data'});
```

Note that setting default values will take precedence
Expand Down
28 changes: 20 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,29 @@
"name": "gaxios",
"version": "6.7.1",
"description": "A simple common HTTP client specifically for Google APIs and services.",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"main": "build/cjs/src/index.js",
"types": "build/cjs/src/index.d.ts",
"files": [
"build/src"
"build/"
],
"exports": {
".": {
"import": {
"types": "./build/esm/src/index.d.ts",
"default": "./build/esm/src/index.js"
},
"require": {
"types": "./build/cjs/src/index.d.ts",
"default": "./build/cjs/src/index.js"
}
}
},
"scripts": {
"lint": "gts check",
"test": "c8 mocha build/test",
"test": "c8 mocha build/esm/test",
"presystem-test": "npm run compile",
"system-test": "mocha build/system-test --timeout 80000",
"compile": "tsc -p .",
"system-test": "mocha build/esm/system-test --timeout 80000",
"compile": "tsc -b ./tsconfig.json ./tsconfig.cjs.json && node utils/enable-esm.mjs",
"fix": "gts fix",
"prepare": "npm run compile",
"pretest": "npm run compile",
Expand All @@ -24,8 +36,7 @@
"predocs-test": "npm run docs",
"samples-test": "cd samples/ && npm link ../ && npm test && cd ../",
"prelint": "cd samples; npm link ../; npm install",
"clean": "gts clean",
"precompile": "gts clean"
"clean": "gts clean"
},
"repository": "googleapis/gaxios",
"keywords": [
Expand Down Expand Up @@ -75,6 +86,7 @@
"ncp": "^2.0.0",
"nock": "^14.0.0-beta.13",
"null-loader": "^4.0.0",
"pack-n-play": "^2.0.3",
"puppeteer": "^23.0.0",
"sinon": "^17.0.0",
"stream-browserify": "^3.0.0",
Expand Down
7 changes: 5 additions & 2 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@

import {Agent} from 'http';
import {URL} from 'url';
import {Readable} from 'stream';

import {pkg} from './util';
import extend from 'extend';
import {Readable} from 'stream';

import util from './util.cjs';

const pkg = util.pkg;

/**
* TypeScript does not have this type available globally - however `@types/node` includes `undici-types`, which has it:
Expand Down
6 changes: 3 additions & 3 deletions src/gaxios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import {
GaxiosPromise,
GaxiosResponse,
defaultErrorRedactor,
} from './common';
import {getRetryConfig} from './retry';
} from './common.js';
import {getRetryConfig} from './retry.js';
import {Readable} from 'stream';
import {GaxiosInterceptorManager} from './interceptor';
import {GaxiosInterceptorManager} from './interceptor.js';

/* eslint-disable @typescript-eslint/no-explicit-any */

Expand Down
8 changes: 4 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import {GaxiosOptions} from './common';
import {Gaxios} from './gaxios';
import {GaxiosOptions} from './common.js';
import {Gaxios} from './gaxios.js';

export {
GaxiosError,
GaxiosPromise,
GaxiosResponse,
GaxiosOptionsPrepared,
RetryConfig,
} from './common';
} from './common.js';
export {Gaxios, GaxiosOptions};
export * from './interceptor';
export * from './interceptor.js';

/**
* The default instance used when the `request` method is directly
Expand Down
2 changes: 1 addition & 1 deletion src/interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import {GaxiosError, GaxiosOptionsPrepared, GaxiosResponse} from './common';
import {GaxiosError, GaxiosOptionsPrepared, GaxiosResponse} from './common.js';

/**
* Interceptors that can be run for requests or responses. These interceptors run asynchronously.
Expand Down
2 changes: 1 addition & 1 deletion src/retry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import {GaxiosError, RetryConfig} from './common';
import {GaxiosError, RetryConfig} from './common.js';

export async function getRetryConfig(err: GaxiosError) {
let config = getConfig(err);
Expand Down
6 changes: 4 additions & 2 deletions src/util.ts → src/util.cts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

export const pkg: {
const pkg: {
name: string;
version: string;
} = require('../../package.json');
} = require('../../../package.json');

export = {pkg};
3 changes: 2 additions & 1 deletion system-test/fixtures/sample/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "gaxios-sample-fixture",
"description": "An app we're using to test the library. ",
"description": "An app we're using to test the library.",
"type": "commonjs",
"scripts": {
"check": "gts check",
"clean": "gts clean",
Expand Down
149 changes: 110 additions & 39 deletions system-test/test.install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,60 +16,131 @@ import assert from 'assert';
import execa from 'execa';
import fs from 'fs';
import mv from 'mv';
import {ncp} from 'ncp';
import ncp from 'ncp';
import path from 'path';
import tmp from 'tmp';
import {promisify} from 'util';
import {describe, it, before, after} from 'mocha';
import {packNTest} from 'pack-n-play';

import {createServer, Server} from 'node:http';

import util from '../src/util.cjs';

/**
* Optionally keep the staging directory between tests.
*/
const KEEP_STAGING_DIRECTORY = false;

const keep = false;
const mvp = promisify(mv) as {} as (...args: string[]) => Promise<void>;
const ncpp = promisify(ncp);
const stagingDir = tmp.dirSync({keep, unsafeCleanup: true});
const stagingPath = stagingDir.name;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const pkg = require('../../package.json');

const pkg = util.pkg;

describe('📦 pack and install', () => {
/**
* Create a staging directory with temp fixtures used to test on a fresh
* application.
*/
before('pack and install', async () => {
await execa('npm', ['pack']);
const tarball = `${pkg.name}-${pkg.version}.tgz`;
await mvp(tarball, `${stagingPath}/gaxios.tgz`);
await ncpp('system-test/fixtures/sample', `${stagingPath}/`);
await execa('npm', ['install'], {
cwd: `${stagingPath}/`,
stdio: 'inherit',
});
});
let stagingDir: tmp.DirResult;
let stagingPath: string;

it('should run the sample', async () => {
await execa('node', ['--throw-deprecation', 'build/src/index.js'], {
cwd: `${stagingPath}/`,
stdio: 'inherit',
before(() => {
stagingDir = tmp.dirSync({
keep: KEEP_STAGING_DIRECTORY,
unsafeCleanup: true,
});
stagingPath = stagingDir.name;
});

it('should be able to webpack the library', async () => {
// we expect npm install is executed in the before hook
await execa('npx', ['webpack'], {
cwd: `${stagingPath}/`,
stdio: 'inherit',
});
const bundle = path.join(stagingPath, 'dist', 'bundle.min.js');
const stat = fs.statSync(bundle);
assert(stat.size < 256 * 1024);
}).timeout(20000);

/**
* CLEAN UP - remove the staging directory when done.
*/
after('cleanup staging', () => {
if (!keep) {
if (!KEEP_STAGING_DIRECTORY) {
stagingDir.removeCallback();
}
});

describe('pack-n-play', () => {
let server: Server;
let url: string;

before(async () => {
server = createServer((req, res) => {
res.writeHead(200, {'content-type': 'text/plain'});
res.end(`Hello, ${req.headers['user-agent'] || 'World'}`);
});

await new Promise<void>((resolve, reject) => {
server.on('error', reject);
server.listen(0, resolve);
});

const address = server.address()!;

if (typeof address === 'string') {
url = address;
} else {
const base = new URL('http://localhost');
base.host = address.address;
base.port = address.port.toString();

url = base.toString();
}
});

after(() => {
server.close();
});

it('supports ESM', async () => {
await packNTest({
sample: {
description: 'import as ESM',
esm: `
import {Gaxios} from 'gaxios';

const gaxios = new Gaxios();
await gaxios.request({url: '${url}'});
`,
},
});
});

it('supports CJS', async () => {
await packNTest({
sample: {
description: 'require as CJS',
cjs: `
const {Gaxios} = require('gaxios');

const gaxios = new Gaxios();
gaxios.request({url: '${url}'}).then(console.log);
`,
},
});
});
});

describe('webpack', () => {
/**
* Create a staging directory with temp fixtures used to test on a fresh
* application.
*/
before('pack and install', async () => {
await execa('npm', ['pack']);
const tarball = `${pkg.name}-${pkg.version}.tgz`;
await mvp(tarball, `${stagingPath}/gaxios.tgz`);
await ncpp('system-test/fixtures/sample', `${stagingPath}/`);
await execa('npm', ['install'], {
cwd: `${stagingPath}/`,
stdio: 'inherit',
});
});

it('should be able to webpack the library', async () => {
// we expect npm install is executed in the before hook
await execa('npx', ['webpack'], {
cwd: `${stagingPath}/`,
stdio: 'inherit',
});
const bundle = path.join(stagingPath, 'dist', 'bundle.min.js');
const stat = fs.statSync(bundle);
assert(stat.size < 256 * 1024);
}).timeout(20000);
});
});
Loading