Skip to content

Commit

Permalink
feat: Monaco Mode - Phase 2 - Mode & Worker (#1459)
Browse files Browse the repository at this point in the history
* custom `graphqlDev` language, graphql webworker and mode
* diagnostics, completion, hover, formatting
* schema loading via config
* new, simplified language service
* example project using webpack, with netlify preview

Co-authored-by: Rikki Schulte <rikki.schulte@gmail.com>
Co-authored-by: Peng Lyu <penlv@microsoft.com>
Co-authored-by: rebornix <penn.lv@gmail.com>
  • Loading branch information
3 people authored Apr 15, 2020
1 parent fddc11d commit bc95fb4
Show file tree
Hide file tree
Showing 34 changed files with 1,677 additions and 47 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
**/flow-typed
**/dist
**/esm
**/bundle
packages/graphiql/webpack
packages/graphiql/storybook
packages/graphiql/lsp
packages/graphiql/monaco
packages/graphiql/*.html
**/renderExample.js
**/*.min.js
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ packages/graphiql/storybook
packages/graphiql/lsp
dist
esm
bundle
cypress/screenshots
node_modules/
npm-debug.log
Expand Down
25 changes: 25 additions & 0 deletions examples/monaco-graphql-webpack/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = {
sourceMaps: true,
presets: [
[
require.resolve('@babel/preset-env'),
{
// corejs: { version: 3, proposals: true },
// useBuiltIns: 'usage',
targets: { browsers: ['last 2 chrome versions'] },
bugfixes: true,
},
],
require.resolve('@babel/preset-typescript'),
],
plugins: [
require.resolve('@babel/plugin-syntax-dynamic-import'),
require.resolve('@babel/plugin-proposal-class-properties'),
[
'@babel/plugin-transform-runtime',
{
regenerator: true,
},
],
],
};
36 changes: 36 additions & 0 deletions examples/monaco-graphql-webpack/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "example-monaco-graphql-webpack",
"version": "1.0.0-alpha.3",
"private": true,
"license": "MIT",
"description": "A simple monaco example with webpack and typescript",
"scripts": {
"build": "cross-env NODE_ENV=production webpack ",
"build-demo": "yarn build && yarn copy-demo",
"copy-demo": "mkdirp ../../packages/graphiql/monaco && copy 'bundle/*' '../../packages/graphiql/monaco'",
"start": "cross-env NODE_ENV=development webpack-dev-server"
},
"dependencies": {
"graphql": "14.6.0",
"monaco-graphql": "^2.3.4-alpha.4",
"prettier": "^2.0.2"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "7.8.3",
"@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/preset-env": "7.9.5",
"@types/prettier": "^2.0.0",
"babel-loader": "^8.1.0",
"cross-env": "^7.0.0",
"css-loader": "^3.5.1",
"html-webpack-plugin": "^4.2.0",
"monaco-editor": "^0.20.0",
"monaco-editor-webpack-plugin": "^1.9.0",
"react-dom": "^16.12.0",
"style-loader": "^1.1.3",
"webpack": "4.42.1",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.1",
"worker-loader": "^2.0.0"
}
}
34 changes: 34 additions & 0 deletions examples/monaco-graphql-webpack/src/index.html.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Monaco Example!</title>
<style>
.div {
margin: 0;
padding: 0;
}
.full-height {
height: 100vh;
}
.column {
width: 50%;
}
</style>
</head>

<body style="margin: 0; padding:0;">
<div style="display: flex;">
<div class="full-height column">
<div id="operation" style="height:70vh;"></div>
<div id="variables" style="height:30vh;"></div>
</div>
<div id="results" class="full-height column"></div>
</div>
</body>

</html>
137 changes: 137 additions & 0 deletions examples/monaco-graphql-webpack/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';

import 'regenerator-runtime/runtime';
import 'monaco-graphql/esm/monaco.contribution';

// NOTE: using loader syntax becuase Yaml worker imports editor.worker directly and that
// import shouldn't go through loader syntax.
// @ts-ignore
import EditorWorker from 'worker-loader!monaco-editor/esm/vs/editor/editor.worker';
// @ts-ignore
import JSONWorker from 'worker-loader!monaco-editor/esm/vs/language/json/json.worker';
// @ts-ignore
import GraphQLWorker from 'worker-loader!monaco-graphql/esm/graphql.worker';

const SCHEMA_URL = 'https://swapi-graphql.netlify.com/.netlify/functions/index';

// @ts-ignore
window.MonacoEnvironment = {
getWorker(_workerId: string, label: string) {
if (label === 'graphqlDev') {
return new GraphQLWorker();
}
if (label === 'json') {
return new JSONWorker();
}
return new EditorWorker();
},
};

// const schemaInput = document.createElement('input');
// schemaInput.type = 'text'

// // @ts-ignore
// schemaInput.value = SCHEMA_URL

// schemaInput.onchange = (e) => {
// e.preventDefault()
// console.log(e.target.value)
// }

// const toolbar = document.getElementById('toolbar')
// toolbar?.appendChild(schemaInput)

const variablesModel = monaco.editor.createModel(
`{}`,
'json',
monaco.Uri.file('/1/variables.json'),
);

const resultsEditor = monaco.editor.create(
document.getElementById('results') as HTMLElement,
{
model: variablesModel,
},
);
const variablesEditor = monaco.editor.create(
document.getElementById('variables') as HTMLElement,
{
value: `{ }`,
language: 'json',
},
);
const model = monaco.editor.createModel(
`
query Example {
allFilms {
films {
id
}
}
}
`,
'graphqlDev',
monaco.Uri.file('/1/operation.graphql'),
);

const operationEditor = monaco.editor.create(
document.getElementById('operation') as HTMLElement,
{
model,
},
);

/**
* Basic Operation Exec Example
*/

async function executeCurrentOp() {
try {
const operation = operationEditor.getValue();
const variables = variablesEditor.getValue();
const body: { variables?: string; query: string } = { query: operation };
const parsedVariables = JSON.parse(variables);
if (parsedVariables && Object.keys(parsedVariables).length) {
body.variables = variables;
}
const result = await fetch(SCHEMA_URL, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(body),
});
const resultText = await result.text();
resultsEditor.setValue(JSON.stringify(JSON.parse(resultText), null, 2));
} catch (err) {
resultsEditor.setValue(err.toString());
}
}

const opAction: monaco.editor.IActionDescriptor = {
id: 'graphql-run',
label: 'Run Operation',
contextMenuOrder: 0,
contextMenuGroupId: 'graphql',
keybindings: [
// eslint-disable-next-line no-bitwise
monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
],
run: executeCurrentOp,
};

operationEditor.addAction(opAction);
variablesEditor.addAction(opAction);
resultsEditor.addAction(opAction);

// add your own diagnostics? why not!
// monaco.editor.setModelMarkers(
// model,
// 'graphql',
// [{
// severity: 5,
// message: 'An example diagnostic error',
// startColumn: 2,
// startLineNumber: 4,
// endLineNumber: 4,
// endColumn: 0,
// }],
// );
18 changes: 18 additions & 0 deletions examples/monaco-graphql-webpack/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": "../../resources/tsconfig.base.cjs.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"composite": true,
"jsx": "preserve",
"baseUrl": ".",
"strictPropertyInitialization": false,
"types": ["node", "jest"],
"typeRoots": ["../../node_modules/@types", "node_modules/@types"],
"lib": ["dom"],
"module": "umd"
},
"references": [{ "path": "../../packages/monaco-graphql" }],
"include": ["src"],
"exclude": ["**/__tests__/**", "**/build/**.*", "../../node_modules"]
}
100 changes: 100 additions & 0 deletions examples/monaco-graphql-webpack/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
const path = require('path');
const webpack = require('webpack');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const isDev = process.env.NODE_ENV === 'development';

const relPath = (...args) => path.resolve(__dirname, ...args);
const rootPath = (...args) => relPath(...args);

const resultConfig = {
mode: process.env.NODE_ENV,
entry: {
app: './index.ts',
'editor.worker': 'monaco-editor/esm/vs/editor/editor.worker.js',
// 'json.worker': 'monaco-editor/esm/vs/language/json/json.worker.js',
'graphql.worker': 'monaco-graphql/esm/graphql.worker.js',
},
context: rootPath('src'),
output: {
path: rootPath('bundle'),
filename: '[name].js',
globalObject: 'self',
},
devServer: {
// bypass simple localhost CORS restrictions by setting
// these to 127.0.0.1 in /etc/hosts
allowedHosts: ['local.example.com', 'monaco-graphql.com'],
},
devtool: isDev ? 'cheap-module-eval-source-map' : 'source-map',
node: {
fs: 'empty',
module: 'empty',
},
module: {
rules: [
// for graphql module, which uses .mjs
{
type: 'javascript/auto',
test: /\.mjs$/,
use: [],
include: /node_modules/,
exclude: /\.(ts|d\.ts|d\.ts\.map)$/,
},
// i think we need to add another rule for
// codemirror-graphql esm.js files to load
{
test: /\.(js|jsx|ts|tsx)$/,
use: [{ loader: 'babel-loader' }],
exclude: /\.(d\.ts|d\.ts\.map|spec\.tsx)$/,
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.svg$/,
use: [{ loader: 'svg-inline-loader' }],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader'],
},
],
},
plugins: [
// in order to prevent async modules for CDN builds
// until we can guarantee it will work with the CDN properly
// and so that graphiql.min.js can retain parity
new HtmlWebpackPlugin({
template: relPath('src/index.html.ejs'),
filename: 'index.html',
}),
new ForkTsCheckerWebpackPlugin({
async: isDev,
tsconfig: rootPath('tsconfig.json'),
}),

new MonacoWebpackPlugin({
languages: ['json'],
}),
],
resolve: {
extensions: ['.mjs', '.js', '.json', '.jsx', '.css', '.ts', '.tsx'],
},
};

if (process.env.ANALYZE) {
resultConfig.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
reportFilename: rootPath('build/analyzer.html'),
}),
);
}

module.exports = resultConfig;
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module.exports = {
'!**/test/**',
'!**/examples/**',
'!**/codemirror-graphql/**',
'!**/monaco-graphql/**',
'!**/graphql-language-service-types/**',
'!**/*.d.ts',
'!**/types.ts',
Expand Down
3 changes: 2 additions & 1 deletion packages/graphiql/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ dist/
esm/
cdn/
webpack/
monaco/
cdn.html
analyzer.html
/graphiql.*js
Expand All @@ -15,4 +16,4 @@ test/pid
/*.html
renderGraphiql.js
cypress/screenshots
.awcache
.awcache
Empty file.
Loading

0 comments on commit bc95fb4

Please sign in to comment.