Skip to content

Commit

Permalink
feat: Remove IE11 support (#2504)
Browse files Browse the repository at this point in the history
* feat: Remove IE11 transpilation and target ES2015-ish

What we'll be targeting from now on is approximately:

```
last 3 ios_saf versions
last 3 and_chr major versions
last 3 samsung major versions
last 3 opera versions
last 3 safari versions
last 10 chrome major versions
last 8 firefox major versions
last 3 edge versions
not ie
not op_mini
not and_uc
```

* Remove transform-function-expressions babel transform

* Update Rollup config

* Update eslint config to allow ES6 static methods and functions

* Remove IE11 support from @urql/exchange-persisted-fetch

* Add changeset

* Deduplicate dependencies

* Fix cjs-check-plugin

* Upgrade @babel/core and terser

* Permit for-of

* Simplif core code where for-of is needed

* Replace dictionaries with Set where for-of may be used

* Replace several dictionaries with maps

* Prevent empty object allocation if possible

* Simplify ast helpers in graphcache

* Tweak ownership and gc timings

* Switch schema checks to Map rather than dictionary

* Upgrade to wonka@^6.0.0

* Remove invalid import from retryExchange

* Upgrade Rollup/Babel and disable Buble's for-of transform

* Rewrite makeFetchURL with URL/URLSearchParams

As these are built-ins in Node 10+ and in all evergreen browsers we
support, we can just use `new URL`

* Remove Buble entirely

* Fix faulty type in retryExchange

* Update new tests for updated data structures
  • Loading branch information
kitten authored Aug 15, 2022
1 parent 600c7b9 commit 05b6911
Show file tree
Hide file tree
Showing 42 changed files with 567 additions and 725 deletions.
23 changes: 23 additions & 0 deletions .changeset/four-flies-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
'@urql/exchange-graphcache': major
'@urql/exchange-persisted-fetch': major
'next-urql': major
'@urql/preact': major
'urql': major
'@urql/storybook-addon': major
'@urql/svelte': major
'@urql/vue': major
'@urql/exchange-auth': major
'@urql/exchange-execute': major
'@urql/exchange-multipart-fetch': major
'@urql/exchange-populate': major
'@urql/exchange-refocus': major
'@urql/exchange-request-policy': major
'@urql/exchange-retry': major
'@urql/core': major
'@urql/introspection': major
'urql-docs': major
'@urql/storage-rn': major
---

**Goodbye IE11!** 👋 This major release removes support for IE11. All code that is shipped will be transpiled much less and will _not_ be ES5-compatible anymore.
20 changes: 20 additions & 0 deletions .changeset/strange-needles-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
'@urql/exchange-auth': major
'@urql/exchange-execute': major
'@urql/exchange-graphcache': major
'@urql/exchange-multipart-fetch': major
'@urql/exchange-persisted-fetch': major
'@urql/exchange-populate': major
'@urql/exchange-refocus': major
'@urql/exchange-request-policy': major
'@urql/exchange-retry': major
'@urql/core': major
'@urql/preact': major
'urql': major
'@urql/storybook-addon': major
'@urql/svelte': major
'@urql/vue': major
---

Upgrade to [Wonka v6](https://github.com/0no-co/wonka) (`wonka@^6.0.0`), which has no breaking changes but is built to target ES2015 and comes with other minor improvements.
The library has fully been migrated to TypeScript which will hopefully help with making contributions easier!
2 changes: 1 addition & 1 deletion exchanges/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
},
"dependencies": {
"@urql/core": ">=2.3.6",
"wonka": "^4.0.14"
"wonka": "^6.0.0"
},
"peerDependencies": {
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
Expand Down
2 changes: 1 addition & 1 deletion exchanges/execute/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
},
"dependencies": {
"@urql/core": ">=2.3.6",
"wonka": "^4.0.14"
"wonka": "^6.0.0"
},
"peerDependencies": {
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
},
"dependencies": {
"@urql/core": ">=2.5.0",
"wonka": "^4.0.14"
"wonka": "^6.0.0"
},
"peerDependencies": {
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
Expand Down
10 changes: 7 additions & 3 deletions exchanges/graphcache/src/ast/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ export const getFragmentTypeName = (node: FragmentDefinitionNode): string =>

/** Returns either the field's name or the field's alias */
export const getFieldAlias = (node: FieldNode): string =>
node.alias ? node.alias.value : getName(node);
node.alias ? node.alias.value : node.name.value;

const emptySelectionSet: SelectionSet = [];

/** Returns the SelectionSet for a given inline or defined fragment node */
export const getSelectionSet = (node: {
selectionSet?: SelectionSetNode;
}): SelectionSet => (node.selectionSet ? node.selectionSet.selections : []);
}): SelectionSet =>
node.selectionSet ? node.selectionSet.selections : emptySelectionSet;

export const getTypeCondition = (node: {
typeCondition?: NamedTypeNode;
}): string | null => (node.typeCondition ? getName(node.typeCondition) : null);
}): string | null =>
node.typeCondition ? node.typeCondition.name.value : null;

export const isFieldNode = (node: SelectionNode): node is FieldNode =>
node.kind === Kind.FIELD;
Expand Down
10 changes: 5 additions & 5 deletions exchanges/graphcache/src/ast/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface SchemaIntrospector {
query: string | null;
mutation: string | null;
subscription: string | null;
types?: Record<string, SchemaObject | SchemaUnion>;
types?: Map<string, SchemaObject | SchemaUnion>;
isSubType(abstract: string, possible: string): boolean;
}

Expand All @@ -47,7 +47,7 @@ export type IntrospectionData =
export const buildClientSchema = ({
__schema,
}: IntrospectionData): SchemaIntrospector => {
const typemap: Record<string, SchemaObject | SchemaUnion> = {};
const typemap: Map<string, SchemaObject | SchemaUnion> = new Map();

const buildNameMap = <T extends { name: string }>(
arr: ReadonlyArray<T>
Expand Down Expand Up @@ -92,8 +92,8 @@ export const buildClientSchema = ({
: null,
types: undefined,
isSubType(abstract: string, possible: string) {
const abstractType = typemap[abstract];
const possibleType = typemap[possible];
const abstractType = typemap.get(abstract);
const possibleType = typemap.get(possible);
if (!abstractType || !possibleType) {
return false;
} else if (abstractType.kind === 'UNION') {
Expand All @@ -115,7 +115,7 @@ export const buildClientSchema = ({
const type = __schema.types[i];
if (type && type.name) {
const out = buildType(type);
if (out) typemap[type.name] = out;
if (out) typemap.set(type.name, out);
}
}
}
Expand Down
38 changes: 20 additions & 18 deletions exchanges/graphcache/src/ast/schemaPredicates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ export const isInterfaceOfType = (
if (!typeCondition || typename === typeCondition) {
return true;
} else if (
schema.types![typeCondition] &&
schema.types![typeCondition].kind === 'OBJECT'
schema.types!.has(typeCondition) &&
schema.types!.get(typeCondition)!.kind === 'OBJECT'
) {
return typeCondition === typename;
}
Expand All @@ -76,7 +76,7 @@ const getField = (
return;

expectObjectType(schema, typename);
const object = schema.types![typename] as SchemaObject;
const object = schema.types!.get(typename) as SchemaObject;
const field = object.fields[fieldName];
if (!field) {
warn(
Expand All @@ -96,7 +96,8 @@ const getField = (

function expectObjectType(schema: SchemaIntrospector, typename: string) {
invariant(
schema.types![typename] && schema.types![typename].kind === 'OBJECT',
schema.types!.has(typename) &&
schema.types!.get(typename)!.kind === 'OBJECT',
'Invalid Object type: The type `' +
typename +
'` is not an object in the defined schema, ' +
Expand All @@ -107,9 +108,9 @@ function expectObjectType(schema: SchemaIntrospector, typename: string) {

function expectAbstractType(schema: SchemaIntrospector, typename: string) {
invariant(
schema.types![typename] &&
(schema.types![typename].kind === 'INTERFACE' ||
schema.types![typename].kind === 'UNION'),
schema.types!.has(typename) &&
(schema.types!.get(typename)!.kind === 'INTERFACE' ||
schema.types!.get(typename)!.kind === 'UNION'),
'Invalid Abstract type: The type `' +
typename +
'` is not an Interface or Union type in the defined schema, ' +
Expand All @@ -124,7 +125,7 @@ export function expectValidKeyingConfig(
): void {
if (process.env.NODE_ENV !== 'production') {
for (const key in keys) {
if (!schema.types![key]) {
if (!schema.types!.has(key)) {
warn(
'Invalid Object type: The type `' +
key +
Expand All @@ -145,7 +146,7 @@ export function expectValidUpdatesConfig(
}

if (schema.mutation) {
const mutationFields = (schema.types![schema.mutation] as SchemaObject)
const mutationFields = (schema.types!.get(schema.mutation) as SchemaObject)
.fields;
const givenMutations = updates[schema.mutation] || {};
for (const fieldName in givenMutations) {
Expand All @@ -161,9 +162,9 @@ export function expectValidUpdatesConfig(
}

if (schema.subscription) {
const subscriptionFields = (schema.types![
const subscriptionFields = (schema.types!.get(
schema.subscription
] as SchemaObject).fields;
) as SchemaObject).fields;
const givenSubscription = updates[schema.subscription] || {};
for (const fieldName in givenSubscription) {
if (subscriptionFields[fieldName] === undefined) {
Expand Down Expand Up @@ -208,7 +209,7 @@ export function expectValidResolversConfig(
for (const key in resolvers) {
if (key === 'Query') {
if (schema.query) {
const validQueries = (schema.types![schema.query] as SchemaObject)
const validQueries = (schema.types!.get(schema.query) as SchemaObject)
.fields;
for (const resolverQuery in resolvers.Query) {
if (!validQueries[resolverQuery]) {
Expand All @@ -219,18 +220,19 @@ export function expectValidResolversConfig(
warnAboutResolver('Query');
}
} else {
if (!schema.types![key]) {
if (!schema.types!.has(key)) {
warnAboutResolver(key);
} else if (
schema.types![key].kind === 'INTERFACE' ||
schema.types![key].kind === 'UNION'
schema.types!.get(key)!.kind === 'INTERFACE' ||
schema.types!.get(key)!.kind === 'UNION'
) {
warnAboutAbstractResolver(
key,
schema.types![key].kind as 'INTERFACE' | 'UNION'
schema.types!.get(key)!.kind as 'INTERFACE' | 'UNION'
);
} else {
const validTypeProperties = (schema.types![key] as SchemaObject).fields;
const validTypeProperties = (schema.types!.get(key) as SchemaObject)
.fields;
for (const resolverProperty in resolvers[key]) {
if (!validTypeProperties[resolverProperty]) {
warnAboutResolver(key + '.' + resolverProperty);
Expand All @@ -250,7 +252,7 @@ export function expectValidOptimisticMutationsConfig(
}

if (schema.mutation) {
const validMutations = (schema.types![schema.mutation] as SchemaObject)
const validMutations = (schema.types!.get(schema.mutation) as SchemaObject)
.fields;
for (const mutation in optimisticMutations) {
if (!validMutations[mutation]) {
Expand Down
12 changes: 5 additions & 7 deletions exchanges/graphcache/src/ast/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,18 @@ export const getFieldArguments = (
node: FieldNode,
vars: Variables
): null | Variables => {
const args = {};
let argsSize = 0;
if (node.arguments && node.arguments.length) {
let args: null | Variables = null;
if (node.arguments) {
for (let i = 0, l = node.arguments.length; i < l; i++) {
const arg = node.arguments[i];
const value = valueFromASTUntyped(arg.value, vars);
if (value !== undefined && value !== null) {
args[getName(arg)] = value;
argsSize++;
if (!args) args = {};
args[getName(arg)] = value as any;
}
}
}

return argsSize > 0 ? args : null;
return args;
};

/** Returns a filtered form of variables with values missing that the query doesn't require */
Expand Down
43 changes: 18 additions & 25 deletions exchanges/graphcache/src/cacheExchange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
} from 'wonka';

import { query, write, writeOptimistic } from './operations';
import { makeDict, isDictEmpty } from './helpers/dict';
import { addCacheOutcome, toRequestPolicy } from './helpers/operation';
import { filterVariables, getMainOperation } from './ast';
import { Store, noopDataState, hydrateData, reserveLayer } from './store';
Expand All @@ -39,7 +38,7 @@ type Operations = Set<number>;
type OperationMap = Map<number, Operation>;
type ResultMap = Map<number, Data | null>;
type OptimisticDependencies = Map<number, Dependencies>;
type DependentOperations = Record<string, number[]>;
type DependentOperations = Map<string, Operations>;

export const cacheExchange = <C extends Partial<CacheExchangeOpts>>(
opts?: C
Expand All @@ -57,29 +56,25 @@ export const cacheExchange = <C extends Partial<CacheExchangeOpts>>(
const mutationResultBuffer: OperationResult[] = [];
const operations: OperationMap = new Map();
const results: ResultMap = new Map();
const blockedDependencies: Dependencies = makeDict();
const blockedDependencies: Dependencies = new Set();
const requestedRefetch: Operations = new Set();
const deps: DependentOperations = makeDict();
const deps: DependentOperations = new Map();

const isBlockedByOptimisticUpdate = (dependencies: Dependencies): boolean => {
for (const dep in dependencies) if (blockedDependencies[dep]) return true;
for (const dep of dependencies.values())
if (blockedDependencies.has(dep)) return true;
return false;
};

const collectPendingOperations = (
pendingOperations: Operations,
dependencies: void | Dependencies
dependencies: undefined | Dependencies
) => {
if (dependencies) {
// Collect operations that will be updated due to cache changes
for (const dep in dependencies) {
const keys = deps[dep];
if (keys) {
deps[dep] = [];
for (let i = 0, l = keys.length; i < l; i++) {
pendingOperations.add(keys[i]);
}
}
for (const dep of dependencies.values()) {
const keys = deps.get(dep);
if (keys) for (const key of keys.values()) pendingOperations.add(key);
}
}
};
Expand All @@ -89,7 +84,7 @@ export const cacheExchange = <C extends Partial<CacheExchangeOpts>>(
pendingOperations: Operations
) => {
// Reexecute collected operations and delete them from the mapping
pendingOperations.forEach(key => {
for (const key of pendingOperations.values()) {
if (key !== operation.key) {
const op = operations.get(key);
if (op) {
Expand All @@ -102,7 +97,7 @@ export const cacheExchange = <C extends Partial<CacheExchangeOpts>>(
client.reexecuteOperation(toRequestPolicy(op, policy));
}
}
});
}
};

// This registers queries with the data layer to ensure commutativity
Expand All @@ -122,11 +117,9 @@ export const cacheExchange = <C extends Partial<CacheExchangeOpts>>(
) {
// This executes an optimistic update for mutations and registers it if necessary
const { dependencies } = writeOptimistic(store, operation, operation.key);
if (!isDictEmpty(dependencies)) {
if (dependencies.size) {
// Update blocked optimistic dependencies
for (const dep in dependencies) {
blockedDependencies[dep] = true;
}
for (const dep of dependencies.values()) blockedDependencies.add(dep);

// Store optimistic dependencies for update
optimisticKeysToDependencies.set(operation.key, dependencies);
Expand Down Expand Up @@ -156,8 +149,10 @@ export const cacheExchange = <C extends Partial<CacheExchangeOpts>>(

// This updates the known dependencies for the passed operation
const updateDependencies = (op: Operation, dependencies: Dependencies) => {
for (const dep in dependencies) {
(deps[dep] || (deps[dep] = [])).push(op.key);
for (const dep of dependencies.values()) {
let depOps = deps.get(dep);
if (!depOps) deps.set(dep, (depOps = new Set()));
depOps.add(op.key);
operations.set(op.key, op);
}
};
Expand Down Expand Up @@ -390,9 +385,7 @@ export const cacheExchange = <C extends Partial<CacheExchangeOpts>>(
reserveLayer(store.data, mutationResultBuffer[i].operation.key);
}

for (const dep in blockedDependencies) {
delete blockedDependencies[dep];
}
blockedDependencies.clear();

const results: OperationResult[] = [];
const pendingOperations: Operations = new Set();
Expand Down
Loading

0 comments on commit 05b6911

Please sign in to comment.