Skip to content

Commit

Permalink
make more optimized graphql-tag/loader
Browse files Browse the repository at this point in the history
  • Loading branch information
k.stoyanov committed Nov 10, 2023
0 parents commit 6781b19
Show file tree
Hide file tree
Showing 14 changed files with 11,720 additions and 0 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 15.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm run test
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
.idea/

# don't commit compiled files
lib
yarn-error.log
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/*.json
8 changes: 8 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"useTabs": false,
"tabWidth": 4,
"jsxSingleQuote": true,
"printWidth": 120,
"singleQuote": true,
"singleAttributePerLine": true
}
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# @evo/graphql-tag-loader

More optimized loader for lib graphql-tag:

If you have configured [the webpack @evo/graphql-tag-loader](#webpack-loading-and-preprocessing), you can import modules containing graphQL queries. The imported value will be the pre-built AST.

```js
import MyQuery from 'query.graphql';
```

#### Importing queries by name

You can also import query and fragment documents by name.

```graphql
query MyQuery1 {
...
}

query MyQuery2 {
...
}
```

And in your JavaScript:

```javascript
import { MyQuery1, MyQuery2 } from 'query.graphql';
```

#### Webpack loading and preprocessing

Using the included `@evo/graphql-tag-loader` it is possible to maintain query logic that is separate from the rest of your application logic. With the loader configured, imported graphQL files will be converted to AST during the webpack build process.

_**Example webpack configuration**_

```js
{
...
loaders: [
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: '@evo/graphql-tag-loader'
}
],
...
}
```
87 changes: 87 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use strict';

const os = require('os');
const gql = require('graphql-tag');
// Takes `source` (the source GraphQL query string)
// and `doc` (the parsed GraphQL document) and tacks on
// the imported definitions.
function expandImports(source) {
const lines = source.split(/\r\n|\r|\n/);
let outputCode = `
var unique = getUniqueFunc();
`;

lines.some((line) => {
const result = line.match(/^#\s?import (.+)$/);
if (result) {
const importFile = result[1];
const parseDocument = `require(${importFile})`;
const appendDef = `doc.definitions = doc.definitions.concat(unique(${parseDocument}.definitions));`;
outputCode += appendDef + os.EOL;
}
return line.length !== 0 && line[0] !== '#';
});

return outputCode;
}

module.exports = function (source) {
const isProduction = process.env.NODE_ENV === 'production';
this.cacheable();
const doc = gql`
${source}
`;
// this getUniqueFunc need for expandImports function
let headerCode = `
var { oneQuery, extractReferences, getUniqueFunc } = require("@evo/graphql-tag-loader/utils.js");
var doc = ${JSON.stringify(doc)};
`;

if (!isProduction) {
headerCode += `doc.loc.source = ${JSON.stringify(doc.loc.source)};`;
}

let outputCode = '';

// Allow multiple query/mutation definitions in a file. This parses out dependencies
// at compile time, and then uses those at load time to create minimal query documents
// We cannot do the latter at compile time due to how the #import code works.
const operationCount = doc.definitions.reduce((accum, op) => {
if (op.kind === 'OperationDefinition' || op.kind === 'FragmentDefinition') {
return accum + 1;
}

return accum;
}, 0);

if (operationCount < 1) {
outputCode += `
module.exports = doc;
`;
} else {
outputCode += `
module.exports = doc;
`;

for (const op of doc.definitions) {
if (op.kind === 'OperationDefinition' || op.kind === 'FragmentDefinition') {
if (!op.name) {
if (operationCount > 1) {
throw new Error('Query/mutation names are required for a document with multiple definitions');
} else {
continue;
}
}

const opName = op.name.value;
outputCode += `
module.exports["${opName}"] = oneQuery(doc, "${opName}", extractReferences(doc));
`;
}
}
}

const importOutputCode = expandImports(source, doc);
const allCode = headerCode + os.EOL + importOutputCode + os.EOL + outputCode + os.EOL;
return allCode;
};
Loading

0 comments on commit 6781b19

Please sign in to comment.