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

draft: merge webpack to vite #2371

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions jest.config.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = (dir, env = 'dom') => {
'\\.(css|less)$': 'identity-obj-proxy',
'^graphql-language-([^/]+)': `${__dirname}/packages/graphql-language-$1/src`,
'^@graphiql-plugins\\/([^/]+)': `${__dirname}/plugins/$1/src`,
'^codemirror-graphql\\/esm\\/([^]+)': `${__dirname}/packages/codemirror-graphql/src/$1`,
'^codemirror-graphql\\/([^]+)': `${__dirname}/packages/codemirror-graphql/src/$1`,
'^example-([^/]+)': `${__dirname}/examples/$1/src`,
},
Expand Down
1 change: 1 addition & 0 deletions packages/graphiql/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ example/graphiql.js
example/graphiql.css
test/pid
/*.html
!index.html
renderGraphiql.js
cypress/screenshots
.awcache
41 changes: 41 additions & 0 deletions packages/graphiql/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!--
* Copyright (c) 2021 GraphQL Contributors
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
-->
<!DOCTYPE html>
<html>
<head>
<style>
body {
height: 100%;
margin: 0;
width: 100%;
overflow: hidden;
}
#graphiql {
height: 100vh;
}
</style>

<!--
This GraphiQL example depends on Promise and fetch, which are available in
modern browsers, but can be "polyfilled" for older browsers.
GraphiQL itself depends on React DOM.
If you do not want to rely on a CDN, you can host these files locally or
include them directly in your favored resource bunder.
-->

<!--
These two files can be found in the npm module, however you may wish to
copy them directly into your environment, or perhaps include them in your
favored resource bundler.
-->
</head>
<body>
<div id="graphiql">Loading...</div>
<script src="./src/main.tsx"></script>
Copy link
Member

@acao acao Apr 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove main.tsx and instead point this to renderGraphiQL.js as we were already doing. it will expect a UMD bundle w/ global GraphiQL, not an esm module. This UMD bundle gets at least 700,000 downloads a month (that's only the stats for jsdelivr, we don't have unpkg stats)!

Copy link
Member

@acao acao Apr 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

</body>
</html>
13 changes: 9 additions & 4 deletions packages/graphiql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,19 @@
],
"scripts": {
"analyze-bundle": "cross-env NODE_ENV=production CDN=1 ANALYZE=1 yarn webpack -p",
"build": "yarn build-clean && yarn build-cjs && yarn build-esm",
"build": "yarn build-cjs && yarn build-esm",
"build-bundles": "yarn build-bundles-clean && yarn build-bundles-dev && yarn build-bundles-min",
"build-bundles-clean": "rimraf 'graphiql.*{js,css}' *.html",
"build-bundles-dev": "cross-env NODE_ENV=development CDN=1 yarn webpack -d --bail",
"build-bundles-min": "cross-env ANALYZE=1 NODE_ENV=production CDN=1 yarn webpack -p --bail",
"build-bundles-clean": "rimraf 'graphiql.*{js,css}'",
"build-bundles-dev": "cross-env NODE_ENV=development CDN=1 yarn vite build --mode dev",
"build-bundles-min": "cross-env ANALYZE=1 NODE_ENV=production CDN=1 vite build",
"build-cjs": "tsc",
"build-clean": "rimraf esm dist webpack *.html",
"build-demo": "build-storybook -o ./storybook",
"build-esm": "tsc --project ./tsconfig.esm.json",
"check": "tsc --noEmit",
"cypress-open": "yarn e2e-server 'cypress open'",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config resources/webpack.config.js",
"dev-vite": "cross-env NODE_ENV=development vite",
"e2e": "yarn e2e-server 'cypress run'",
"e2e-server": "start-server-and-test 'cross-env PORT=8080 node test/e2e-server' 'http-get://localhost:8080/graphql?query={test { id }}'",
"storybook": "start-storybook",
Expand All @@ -62,6 +63,10 @@
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"devDependencies": {
"router": "^1.3.6",
"vite": "^2.9.5",
"@vitejs/plugin-react-refresh": "^1.3.6",
"rollup-plugin-visualizer": "^5.6.0",
"@testing-library/jest-dom": "^5.4.0",
"@testing-library/react": "9.4.1",
"@types/codemirror": "^5.58.2",
Expand Down
10 changes: 5 additions & 5 deletions packages/graphiql/src/components/QueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ export class QueryEditor extends React.Component<QueryEditorProps, {}>
addonModules = () => [
import('codemirror/addon/comment/comment'),
import('codemirror/addon/search/search'),
import('codemirror-graphql/hint'),
import('codemirror-graphql/lint'),
import('codemirror-graphql/info'),
import('codemirror-graphql/jump'),
import('codemirror-graphql/mode'),
import('codemirror-graphql/esm/hint'),
import('codemirror-graphql/esm/lint'),
import('codemirror-graphql/esm/info'),
import('codemirror-graphql/esm/jump'),
import('codemirror-graphql/esm/mode'),
];

async initializeEditor() {
Expand Down
4 changes: 2 additions & 2 deletions packages/graphiql/src/components/ResultViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class ResultViewer extends React.Component<ResultViewerProps, {}>
import('codemirror/addon/search/jump-to-line'),
// @ts-expect-error
import('codemirror/keymap/sublime'),
import('codemirror-graphql/results/mode'),
import('codemirror-graphql/esm/results/mode'),
];

async initializeEditor() {
Expand All @@ -94,7 +94,7 @@ export class ResultViewer extends React.Component<ResultViewerProps, {}>
const ImagePreview = this.props.ImagePreview;

if (Tooltip || ImagePreview) {
await import('codemirror-graphql/utils/info-addon');
await import('codemirror-graphql/esm/utils/info-addon');
const tooltipDiv = document.createElement('div');
CodeMirror.registerHelper(
'info',
Expand Down
6 changes: 3 additions & 3 deletions packages/graphiql/src/components/VariableEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ export class VariableEditor extends React.Component<VariableEditorProps> {
}

addonModules = () => [
import('codemirror-graphql/variables/hint'),
import('codemirror-graphql/variables/lint'),
import('codemirror-graphql/variables/mode'),
import('codemirror-graphql/esm/variables/hint'),
import('codemirror-graphql/esm/variables/lint'),
import('codemirror-graphql/esm/variables/mode'),
];

async initializeEditor() {
Expand Down
188 changes: 188 additions & 0 deletions packages/graphiql/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/**
Copy link
Member

@acao acao Apr 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, this file just needs to be removed from this PR. it should instead import renderGraphiQL.js as before, which does not contain any typescript, and uses the UMD global

* UMD GraphiQL Example
*
* This is a simple example that provides a primitive query string parser on top of GraphiQL props
* It assumes a global umd GraphiQL, which would be provided by an index.html in the default example
*
* It is used by:
* - the netlify demo
* - end to end tests
* - webpack dev server
*/

import React from 'react';
Copy link
Member

@acao acao Apr 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file should not contain imports. this example was meant to be a CDN usage example, that tests the CDN example using the UMD without esm or any bundling. this example implementaiton is not a file for users to import, I hope that's clear. the vast amount of our users use the unpkg/jsdelivr bundle, not the esm import and a bundler. please see the comment at the top of this file

import ReactDOM from 'react-dom';
import GraphiQL from './cdn';
import './css/app.css';
import './css/codemirror.css';
import './css/foldgutter.css';
import './css/info.css';
import './css/jump.css';
import './css/lint.css';
import './css/loading.css';
import './css/show-hint.css';

import './css/doc-explorer.css';
import './css/history.css';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how this file ended up in src (maybe I moved it?) but it should not be part of the resulting build. It's meant to just be an example implementation. It should be example.js, and not be a typescript file. The bundler should not pick up this file

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it seems that I didn't notice that tsc will compile all the files in the directory, and src/main.tsx is only used as the entry script of the web application (the official practice of the vite project). Probably should be excluded from tsc or moved to resources/ directory

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, yes src/main.tsx should be src/example.js and should not be used as the bundling entry point, that should be src/cdn.js if you see in the webpack config. I originally had this file in the resources/ directory, it must have been moved during the tabs effort. src/index.js is the ESM main, which is different, and not what you want to treat as the entrypoint with vite.

Copy link
Author

@rxliuli rxliuli Apr 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, I excluded src/main.tsx from tsconfig.json/tsconfig.esm.json
1a0a3ef

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file should not be importing individual css files either, the idea is that it's supposed to show a demo using the CDN bundle and thus the css bundle... I need to clean this file up in another PR!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huh weird, webpack supports it for umd by just un-splitting the code and inlining the dynamic imports. this is going to be a big problem then.

Copy link
Member

@acao acao Apr 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the esm bundle users want dynamic imports for SSR, and the cdn users just want a single file and don't really need dynamic imports. there has to be a way? we originally were using inline require() statements when I inherited the project, as dynamic import was only a proposal then, but now esbuild can't handle that, so we switched to modern dynamic imports for codemirror/etc, which requires window to be present on import (thus why we can't import top-level)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rxliuli it seems some of these solutions might work:

vitejs/vite#2982

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I played around with this too recently. There's a option that inlines all dynamic imports:

export default defineConfig({
  // ...
  build: {
    lib: { /* libarary mode */ },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: { inlineDynamicImports: true },
    },
  },
});

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

brilliant!


// Parse the search string to get url parameters.
const search = window.location.search;
const parameters = {};
search
.substr(1)
.split('&')
.forEach(function (entry) {
const eq = entry.indexOf('=');
if (eq >= 0) {
// @ts-expect-error
parameters[decodeURIComponent(entry.slice(0, eq))] = decodeURIComponent(
entry.slice(eq + 1),
);
}
});

// If variables was provided, try to format it.
// @ts-expect-error
if (parameters.variables) {
try {
// @ts-expect-error
parameters.variables = JSON.stringify(
// @ts-expect-error
JSON.parse(parameters.variables),
null,
2,
);
} catch (e) {
// Do nothing, we want to display the invalid JSON as a string, rather
// than present an error.
}
}

// If headers was provided, try to format it.
// @ts-expect-error
if (parameters.headers) {
try {
// @ts-expect-error
parameters.headers = JSON.stringify(
// @ts-expect-error
JSON.parse(parameters.headers),
null,
2,
);
} catch (e) {
// Do nothing, we want to display the invalid JSON as a string, rather
// than present an error.
}
}

// When the query and variables string is edited, update the URL bar so
// that it can be easily shared.
// @ts-expect-error
function onEditQuery(newQuery) {
// @ts-expect-error
parameters.query = newQuery;
updateURL();
}

// @ts-expect-error
function onEditVariables(newVariables) {
// @ts-expect-error
parameters.variables = newVariables;
updateURL();
}

// @ts-expect-error
function onEditHeaders(newHeaders) {
// @ts-expect-error
parameters.headers = newHeaders;
updateURL();
}

// @ts-expect-error
function onEditOperationName(newOperationName) {
// @ts-expect-error
parameters.operationName = newOperationName;
updateURL();
}

// @ts-expect-error
function onTabChange(tabsState) {
const activeTab = tabsState.tabs[tabsState.activeTabIndex];
// @ts-expect-error
parameters.query = activeTab.query;
// @ts-expect-error
parameters.variables = activeTab.variables;
// @ts-expect-error
parameters.headers = activeTab.headers;
// @ts-expect-error
parameters.operationName = activeTab.operationName;
updateURL();
}

function updateURL() {
const newSearch =
'?' +
Object.keys(parameters)
.filter(function (key) {
// @ts-expect-error
return Boolean(parameters[key]);
})
.map(function (key) {
return (
// @ts-expect-error
encodeURIComponent(key) + '=' + encodeURIComponent(parameters[key])
);
})
.join('&');
// @ts-expect-error
history.replaceState(null, null, newSearch);
}

function getSchemaUrl() {
const isDev = window.location.hostname.match(/localhost$/);

if (isDev) {
// This supports an e2e test which ensures that invalid schemas do not load.
// @ts-expect-error
if (parameters.bad && parameters.bad === 'true') {
return '/bad/graphql';
} else {
return '/graphql';
}
}
return '/.netlify/functions/schema-demo';
}

// Render <GraphiQL /> into the body.
// See the README in the top level of this module to learn more about
// how you can customize GraphiQL by providing different values or
// additional child elements.
ReactDOM.render(
React.createElement(GraphiQL, {
// @ts-expect-error
fetcher: GraphiQL.createFetcher({
url: getSchemaUrl(),
subscriptionUrl: 'ws://localhost:8081/subscriptions',
}),
// @ts-expect-error
query: parameters.query,
// @ts-expect-error
variables: parameters.variables,
// @ts-expect-error
headers: parameters.headers,
// @ts-expect-error
operationName: parameters.operationName,
onEditQuery,
onEditVariables,
onEditHeaders,
defaultSecondaryEditorOpen: true,
onEditOperationName,
headerEditorEnabled: true,
shouldPersistHeaders: true,
inputValueDeprecation: true,
tabs: {
onTabChange,
},
}),
document.getElementById('graphiql'),
);
1 change: 1 addition & 0 deletions packages/graphiql/tsconfig.esm.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"include": ["src"],
"exclude": [
"src/main.tsx",
"**/__tests__/**",
"**/dist/**.*",
"**/*.spec.ts",
Expand Down
5 changes: 4 additions & 1 deletion packages/graphiql/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
"outDir": "./dist",
"composite": true,
"jsx": "react",
"target": "es5",
"target": "ESNext",
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"strictPropertyInitialization": false
},
"include": ["src"],
"exclude": [
"src/main.tsx",
"**/__tests__/**",
"**/dist/**.*",
"**/*.spec.ts",
Expand Down