Webpack 5 support with updated packages (#131)
- Update to Webpack 5 - Use @effortlessmotion dynamic html and inline source plugins - Remove .clasp.json and use SAMPLE file - Consistent prettier formatting throughout - Update packages to latest versions Co-authored-by: Kevin Malakoff <kmalakoff@gmail.com>
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"rootDir": "dist",
|
||||
"scriptId": "...add scriptId here..."
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"rootDir": "dist",
|
||||
"scriptId": "...add scriptId here...",
|
||||
"parentId": [
|
||||
"...spreadsheet/doc url ID here..."
|
||||
]
|
||||
}
|
||||
@@ -10,5 +10,10 @@
|
||||
"import/no-extraneous-dependencies": "warn",
|
||||
"prefer-object-spread": "warn",
|
||||
"spaced-comment":"off"
|
||||
},
|
||||
"parserOptions": {
|
||||
"babelOptions": {
|
||||
"configFile": "./dev/.babelrc"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
node_modules
|
||||
|
||||
# clasp files
|
||||
.clasp*
|
||||
creds.json
|
||||
|
||||
# certs
|
||||
|
||||
@@ -113,7 +113,7 @@ You will need to update the `.clasp.json` file in the root of this project with
|
||||
{
|
||||
"scriptId": "1PY037hPcy................................................",
|
||||
"parentId": ["1Df30......................................."],
|
||||
"rootDir": "./dist"
|
||||
"rootDir": "dist"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -7,20 +7,20 @@ const { FILENAME, PORT } = process.env;
|
||||
const DevServer = () => {
|
||||
const iframe = React.useRef(null);
|
||||
useEffect(() => {
|
||||
const handleRequest = event => {
|
||||
const handleRequest = (event) => {
|
||||
const request = event.data;
|
||||
const { type, functionName, id, args } = request;
|
||||
|
||||
if (type !== 'REQUEST') return;
|
||||
|
||||
serverFunctions[functionName](...args)
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
iframe.current.contentWindow.postMessage(
|
||||
{ type: 'RESPONSE', id, status: 'SUCCESS', response },
|
||||
`https://localhost:${PORT}`
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
iframe.current.contentWindow.postMessage(
|
||||
{
|
||||
type: 'RESPONSE',
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test:integration": "jest --forceExit test/local-development.test",
|
||||
"test:integration:extended": "cross-env IS_EXTENDED=1 jest --forceExit test/local-development.test",
|
||||
"test:integration:extended": "cross-env IS_EXTENDED=true jest --forceExit test/local-development.test",
|
||||
"login": "clasp login",
|
||||
"setup": "rimraf .clasp.json && clasp create --type sheets --title \"My React Project\" --rootDir ./dist",
|
||||
"open": "clasp open --addon",
|
||||
@@ -17,7 +17,7 @@
|
||||
"build": "cross-env NODE_ENV=production webpack",
|
||||
"deploy:dev": "rimraf dist && npm run build:dev && npx clasp push",
|
||||
"deploy": "rimraf dist && npm run build && npx clasp push",
|
||||
"serve": "cross-env NODE_ENV=development webpack-dev-server",
|
||||
"serve": "cross-env NODE_ENV=development webpack serve",
|
||||
"start": "npm run deploy:dev && npm run serve"
|
||||
},
|
||||
"keywords": [
|
||||
@@ -35,75 +35,75 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^17.0.2",
|
||||
"react-bootstrap": "^1.6.4",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.4.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-transition-group": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.17.6",
|
||||
"@babel/core": "^7.17.8",
|
||||
"@babel/eslint-parser": "^7.17.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.16.7",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.17.3",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.17.12",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.18.0",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.17.12",
|
||||
"@babel/plugin-transform-object-assign": "^7.16.7",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@babel/preset-react": "^7.16.7",
|
||||
"@google/clasp": "2.3.1",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@types/expect-puppeteer": "^4.4.7",
|
||||
"@types/jest-environment-puppeteer": "^4.4.1",
|
||||
"@types/puppeteer": "^5.4.5",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-react": "^7.17.12",
|
||||
"@effortlessmotion/dynamic-cdn-webpack-plugin": "^5.0.1",
|
||||
"@effortlessmotion/html-webpack-inline-source-plugin": "^1.0.3",
|
||||
"@google/clasp": "^2.4.1",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
|
||||
"@types/expect-puppeteer": "^5.0.0",
|
||||
"@types/jest-environment-puppeteer": "^5.0.2",
|
||||
"@types/puppeteer": "^5.4.6",
|
||||
"@types/react": "^18.0.14",
|
||||
"aws-sdk": "^2.1106.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.2.4",
|
||||
"babel-plugin-add-module-exports": "^1.0.2",
|
||||
"babel-loader": "^8.2.5",
|
||||
"babel-plugin-add-module-exports": "^1.0.4",
|
||||
"babel-plugin-transform-es3-member-expression-literals": "^6.22.0",
|
||||
"babel-plugin-transform-es3-property-literals": "^6.22.0",
|
||||
"copy-webpack-plugin": "^6.4.1",
|
||||
"cross-env": "^7.0.2",
|
||||
"css-loader": "^3.6.0",
|
||||
"dotenv": "^8.6.0",
|
||||
"dynamic-cdn-webpack-plugin": "^5.0.0",
|
||||
"eslint": "^8.12.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.1",
|
||||
"dotenv": "^16.0.1",
|
||||
"eslint": "^8.17.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-config-standard": "^17.0.0",
|
||||
"eslint-plugin-babel": "^5.3.1",
|
||||
"eslint-plugin-googleappsscript": "^1.0.4",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^26.1.3",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jest": "^26.5.3",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^3.4.1",
|
||||
"eslint-plugin-promise": "^4.3.1",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-promise": "^6.0.0",
|
||||
"eslint-plugin-react": "^7.30.0",
|
||||
"eslint-plugin-standard": "^5.0.0",
|
||||
"gas-client": "^1.0.0",
|
||||
"gas-lib": "^2.0.4",
|
||||
"gas-types-detailed": "^1.0.0",
|
||||
"gas-webpack-plugin": "^1.2.3",
|
||||
"html-webpack-inline-source-plugin": "0.0.10",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-environment-node": "^27.5.1",
|
||||
"jest-image-snapshot": "^4.5.1",
|
||||
"gas-webpack-plugin": "^2.2.2",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"jest": "^28.1.1",
|
||||
"jest-environment-node": "^28.1.1",
|
||||
"jest-image-snapshot": "^5.1.0",
|
||||
"mkdirp": "^1.0.4",
|
||||
"module-to-cdn": "^3.1.5",
|
||||
"prettier": "^1.19.1",
|
||||
"puppeteer": "^13.5.2",
|
||||
"prettier": "^2.7.0",
|
||||
"puppeteer": "^14.3.0",
|
||||
"puppeteer-extra": "^3.2.3",
|
||||
"puppeteer-extra-plugin-stealth": "^2.9.0",
|
||||
"react-refresh": "^0.10.0",
|
||||
"react-refresh": "^0.14.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"style-loader": "^1.3.0",
|
||||
"tern": "^0.24.3",
|
||||
"terser-webpack-plugin": "^2.3.8",
|
||||
"ts-loader": "^8.3.0",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.3"
|
||||
"style-loader": "^3.3.1",
|
||||
"terser-webpack-plugin": "^5.3.3",
|
||||
"ts-loader": "^9.3.0",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.9.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@ import React, { useState, ChangeEvent, FormEvent } from 'react';
|
||||
import { Form, Button, Col, Row } from 'react-bootstrap';
|
||||
|
||||
interface FormInputProps {
|
||||
submitNewSheet: (
|
||||
sheetName: string
|
||||
) => {
|
||||
submitNewSheet: (sheetName: string) => {
|
||||
name: string;
|
||||
index: number;
|
||||
isActive: boolean;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { TransitionGroup, CSSTransition } from 'react-transition-group';
|
||||
import { Button, ListGroup } from 'react-bootstrap';
|
||||
import FormInput from './FormInput.tsx';
|
||||
import FormInput from './FormInput';
|
||||
|
||||
// This is a wrapper for google.script.run that lets us use promises.
|
||||
import { serverFunctions } from '../../utils/serverFunctions';
|
||||
@@ -10,27 +10,18 @@ const SheetEditor = () => {
|
||||
const [names, setNames] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
serverFunctions
|
||||
.getSheetsData()
|
||||
.then(setNames)
|
||||
.catch(alert);
|
||||
serverFunctions.getSheetsData().then(setNames).catch(alert);
|
||||
}, []);
|
||||
|
||||
const deleteSheet = sheetIndex => {
|
||||
serverFunctions
|
||||
.deleteSheet(sheetIndex)
|
||||
.then(setNames)
|
||||
.catch(alert);
|
||||
const deleteSheet = (sheetIndex) => {
|
||||
serverFunctions.deleteSheet(sheetIndex).then(setNames).catch(alert);
|
||||
};
|
||||
|
||||
const setActiveSheet = sheetName => {
|
||||
serverFunctions
|
||||
.setActiveSheet(sheetName)
|
||||
.then(setNames)
|
||||
.catch(alert);
|
||||
const setActiveSheet = (sheetName) => {
|
||||
serverFunctions.setActiveSheet(sheetName).then(setNames).catch(alert);
|
||||
};
|
||||
|
||||
const submitNewSheet = async newSheetName => {
|
||||
const submitNewSheet = async (newSheetName) => {
|
||||
try {
|
||||
const response = await serverFunctions.addSheet(newSheetName);
|
||||
setNames(response);
|
||||
@@ -56,7 +47,7 @@ const SheetEditor = () => {
|
||||
<ListGroup>
|
||||
<TransitionGroup className="sheet-list">
|
||||
{names.length > 0 &&
|
||||
names.map(name => (
|
||||
names.map((name) => (
|
||||
<CSSTransition
|
||||
classNames="sheetNames"
|
||||
timeout={500}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* needed to make consistent test snapshots across OSs */
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif !important;
|
||||
font-family: Arial !important;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -4,9 +4,9 @@ import PropTypes from 'prop-types';
|
||||
const FormInput = ({ submitNewSheet }) => {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
|
||||
const handleChange = event => setInputValue(event.target.value);
|
||||
const handleChange = (event) => setInputValue(event.target.value);
|
||||
|
||||
const handleSubmit = event => {
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
if (inputValue.length === 0) return;
|
||||
|
||||
|
||||
@@ -11,29 +11,20 @@ const SheetEditor = () => {
|
||||
|
||||
useEffect(() => {
|
||||
// Call a server global function here and handle the response with .then() and .catch()
|
||||
serverFunctions
|
||||
.getSheetsData()
|
||||
.then(setNames)
|
||||
.catch(alert);
|
||||
serverFunctions.getSheetsData().then(setNames).catch(alert);
|
||||
}, []);
|
||||
|
||||
const deleteSheet = sheetIndex => {
|
||||
serverFunctions
|
||||
.deleteSheet(sheetIndex)
|
||||
.then(setNames)
|
||||
.catch(alert);
|
||||
const deleteSheet = (sheetIndex) => {
|
||||
serverFunctions.deleteSheet(sheetIndex).then(setNames).catch(alert);
|
||||
};
|
||||
|
||||
const setActiveSheet = sheetName => {
|
||||
serverFunctions
|
||||
.setActiveSheet(sheetName)
|
||||
.then(setNames)
|
||||
.catch(alert);
|
||||
const setActiveSheet = (sheetName) => {
|
||||
serverFunctions.setActiveSheet(sheetName).then(setNames).catch(alert);
|
||||
};
|
||||
|
||||
// You can also use async/await notation for server calls with our server wrapper.
|
||||
// (This does the same thing as .then().catch() in the above handlers.)
|
||||
const submitNewSheet = async newSheetName => {
|
||||
const submitNewSheet = async (newSheetName) => {
|
||||
try {
|
||||
const response = await serverFunctions.addSheet(newSheetName);
|
||||
setNames(response);
|
||||
@@ -56,7 +47,7 @@ const SheetEditor = () => {
|
||||
<FormInput submitNewSheet={submitNewSheet} />
|
||||
<TransitionGroup className="sheet-list">
|
||||
{names.length > 0 &&
|
||||
names.map(name => (
|
||||
names.map((name) => (
|
||||
<CSSTransition
|
||||
classNames="sheetNames"
|
||||
timeout={500}
|
||||
|
||||
@@ -14,20 +14,18 @@ export const getSheetsData = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const addSheet = sheetTitle => {
|
||||
export const addSheet = (sheetTitle) => {
|
||||
SpreadsheetApp.getActive().insertSheet(sheetTitle);
|
||||
return getSheetsData();
|
||||
};
|
||||
|
||||
export const deleteSheet = sheetIndex => {
|
||||
export const deleteSheet = (sheetIndex) => {
|
||||
const sheets = getSheets();
|
||||
SpreadsheetApp.getActive().deleteSheet(sheets[sheetIndex]);
|
||||
return getSheetsData();
|
||||
};
|
||||
|
||||
export const setActiveSheet = sheetName => {
|
||||
SpreadsheetApp.getActive()
|
||||
.getSheetByName(sheetName)
|
||||
.activate();
|
||||
export const setActiveSheet = (sheetName) => {
|
||||
SpreadsheetApp.getActive().getSheetByName(sheetName).activate();
|
||||
return getSheetsData();
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 40 KiB |
@@ -25,10 +25,13 @@ const srcTestFile = path.join(
|
||||
'../src/client/dialog-demo-bootstrap/components/SheetEditor.jsx'
|
||||
);
|
||||
|
||||
const webpackDevServerReady = async process => {
|
||||
return new Promise(resolve => {
|
||||
process.stdout.on('data', data => {
|
||||
if (data.includes('Compiled successfully.')) resolve();
|
||||
const webpackDevServerReady = async (process) => {
|
||||
console.log('Waiting for Webpack Dev Server to finish loading...');
|
||||
return new Promise((resolve) => {
|
||||
process.stdout.on('data', (data) => {
|
||||
if (data.includes('DEVELOPMENT: CLIENT - Dialog Demo Bootstrap')) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,11 +6,15 @@ const { readFile } = require('fs').promises;
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const puppeteer = require('puppeteer');
|
||||
const NodeEnvironment = require('jest-environment-node');
|
||||
const NodeEnvironment = require('jest-environment-node').default;
|
||||
|
||||
const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
|
||||
|
||||
class PuppeteerEnvironment extends NodeEnvironment {
|
||||
constructor(config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
async setup() {
|
||||
await super.setup();
|
||||
// get the wsEndpoint
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
|
||||
/**
|
||||
* Reference: https://github.com/americanexpress/jest-image-snapshot/blob/main/examples/image-reporter.js
|
||||
*
|
||||
*
|
||||
* To enable this image reporter, add it to your `jest.config.js` "reporters" definition:
|
||||
* "reporters": [ "default", "<rootDir>/image-reporter.js" ]
|
||||
*
|
||||
* Image Reporter may not work with jest's --forceExit flag
|
||||
*
|
||||
* Note: Image Reporter may not work with jest's --forceExit flag
|
||||
*
|
||||
* Note: If image reporter doesn't work in pipeline can try running as standalone script
|
||||
* by creating a separate script file and running like this:
|
||||
* "test:integration": "jest test/local-development.test || node test/utils/image-reporter-standalone.js"
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
@@ -44,9 +48,9 @@ class ImageReporter {
|
||||
'./test/__image_snapshots__/',
|
||||
'./test/__image_snapshots__/__diff_output__/',
|
||||
];
|
||||
targetDirectories.forEach(targetDirectory => {
|
||||
targetDirectories.forEach((targetDirectory) => {
|
||||
fs.readdirSync(targetDirectory, { withFileTypes: true }).forEach(
|
||||
dirent => {
|
||||
(dirent) => {
|
||||
if (!dirent.isFile()) return;
|
||||
const path = `images/${dirent.name}`;
|
||||
const params = {
|
||||
@@ -55,7 +59,7 @@ class ImageReporter {
|
||||
Key: path,
|
||||
ContentType: 'image/png',
|
||||
};
|
||||
s3.putObject(params, err => {
|
||||
s3.putObject(params, (err) => {
|
||||
if (err) {
|
||||
console.log(err, err.stack);
|
||||
} else {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const openAddon = async page => {
|
||||
const openAddon = async (page) => {
|
||||
await page.goto(process.env.SHEET_URL);
|
||||
|
||||
await page.click('a:nth-child(2)'); // click on signin button
|
||||
@@ -22,7 +22,7 @@ const openAddon = async page => {
|
||||
)
|
||||
) {
|
||||
try {
|
||||
await page.click('div[data-accountrecovery]');
|
||||
await page.click('li:nth-child(3)');
|
||||
await page.waitForTimeout(6000);
|
||||
} catch {
|
||||
// eslint-disable-next-line no-console
|
||||
|
||||
@@ -8,8 +8,8 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const GasPlugin = require('gas-webpack-plugin');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
|
||||
const DynamicCdnWebpackPlugin = require('dynamic-cdn-webpack-plugin');
|
||||
const HtmlWebpackInlineSourcePlugin = require('@effortlessmotion/html-webpack-inline-source-plugin');
|
||||
const DynamicCdnWebpackPlugin = require('@effortlessmotion/dynamic-cdn-webpack-plugin');
|
||||
const moduleToCdn = require('module-to-cdn');
|
||||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||
|
||||
@@ -25,6 +25,7 @@ envVars.NODE_ENV = process.env.NODE_ENV;
|
||||
envVars.PORT = PORT;
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const publicPath = process.env.ASSET_PATH || '/';
|
||||
|
||||
/*********************************
|
||||
* define entrypoints
|
||||
@@ -80,6 +81,7 @@ const copyFilesConfig = {
|
||||
entry: copyAppscriptEntry,
|
||||
output: {
|
||||
path: destination,
|
||||
publicPath,
|
||||
},
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
@@ -107,12 +109,19 @@ const clientConfig = ({ isDevClientWrapper }) => ({
|
||||
// this file will get added to the html template inline
|
||||
// and should be put in .claspignore so it is not pushed
|
||||
filename: 'main.js',
|
||||
publicPath,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
// typescript config
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
@@ -174,11 +183,6 @@ const DynamicCdnWebpackPluginConfig = {
|
||||
return null;
|
||||
}
|
||||
|
||||
// return defaults if Dynamic CDN plugin finds package
|
||||
if (moduleDetails) {
|
||||
return moduleDetails;
|
||||
}
|
||||
|
||||
// define custom CDN configuration for new packages
|
||||
// "name" should match the package being imported
|
||||
// "var" is important to get right -- this should be the exposed global. Look up "webpack externals" for info.
|
||||
@@ -197,21 +201,29 @@ const DynamicCdnWebpackPluginConfig = {
|
||||
version: packageVersion,
|
||||
url: `https://unpkg.com/react-bootstrap@${packageVersion}/dist/react-bootstrap${packageSuffix}`,
|
||||
};
|
||||
// must include peer dependencies for any custom imports
|
||||
case '@types/react':
|
||||
return {
|
||||
name: packageName,
|
||||
var: '@types/react',
|
||||
version: packageVersion,
|
||||
url: `https://unpkg.com/@types/react@${packageVersion}/index.d.ts`,
|
||||
};
|
||||
// return defaults/null depending if Dynamic CDN plugin finds package
|
||||
default:
|
||||
return null;
|
||||
return moduleDetails;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// webpack settings used by each client entrypoint defined at top
|
||||
const clientConfigs = clientEntrypoints.map(clientEntrypoint => {
|
||||
const clientConfigs = clientEntrypoints.map((clientEntrypoint) => {
|
||||
const isDevClientWrapper = false;
|
||||
return {
|
||||
...clientConfig({ isDevClientWrapper }),
|
||||
name: clientEntrypoint.name,
|
||||
entry: clientEntrypoint.entry,
|
||||
plugins: [
|
||||
!isProd && new webpack.HotModuleReplacementPlugin(),
|
||||
!isProd && new ReactRefreshWebpackPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': JSON.stringify(envVars),
|
||||
@@ -219,7 +231,9 @@ const clientConfigs = clientEntrypoints.map(clientEntrypoint => {
|
||||
new HtmlWebpackPlugin({
|
||||
template: clientEntrypoint.template,
|
||||
filename: `${clientEntrypoint.filename}${isProd ? '' : '-impl'}.html`,
|
||||
inlineSource: '^[^(//)]+.(js|css)$', // embed all js and css inline, exclude packages with '//' for dynamic cdn insertion
|
||||
inlineSource: '^/.*(js|css)$', // embed all js and css inline, exclude packages from dynamic cdn insertion
|
||||
scriptLoading: 'blocking',
|
||||
inject: 'body',
|
||||
}),
|
||||
// add the generated js code to the html file inline
|
||||
new HtmlWebpackInlineSourcePlugin(),
|
||||
@@ -233,14 +247,14 @@ const clientConfigs = clientEntrypoints.map(clientEntrypoint => {
|
||||
const devServer = {
|
||||
hot: true,
|
||||
port: PORT,
|
||||
https: true,
|
||||
server: 'https',
|
||||
};
|
||||
|
||||
if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
|
||||
// use key and cert settings only if they are found
|
||||
devServer.https = {
|
||||
key: fs.readFileSync(keyPath),
|
||||
cert: fs.readFileSync(certPath),
|
||||
devServer.server = {
|
||||
type: 'https',
|
||||
options: { key: fs.readFileSync(keyPath), cert: fs.readFileSync(certPath) },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -248,14 +262,14 @@ if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
|
||||
// script at test/generate-cert.ps1 can be used to create a .pfx cert
|
||||
if (fs.existsSync(pfxPath)) {
|
||||
// use pfx file if it's found
|
||||
devServer.https = {
|
||||
pfx: fs.readFileSync(pfxPath),
|
||||
passphrase: 'abc123',
|
||||
devServer.server = {
|
||||
type: 'https',
|
||||
options: { pfx: fs.readFileSync(pfxPath), passphrase: 'abc123' },
|
||||
};
|
||||
}
|
||||
|
||||
// webpack settings for the development client wrapper
|
||||
const devClientConfigs = clientEntrypoints.map(clientEntrypoint => {
|
||||
const devClientConfigs = clientEntrypoints.map((clientEntrypoint) => {
|
||||
envVars.FILENAME = clientEntrypoint.filename;
|
||||
const isDevClientWrapper = true;
|
||||
return {
|
||||
@@ -270,7 +284,9 @@ const devClientConfigs = clientEntrypoints.map(clientEntrypoint => {
|
||||
template: './dev/index.html',
|
||||
// this should match the html files we load in src/server/ui.js
|
||||
filename: `${clientEntrypoint.filename}.html`,
|
||||
inlineSource: '^[^(//)]+.(js|css)$', // embed all js and css inline, exclude packages with '//' for dynamic cdn insertion
|
||||
inlineSource: '^/.*(js|css)$', // embed all js and css inline, exclude packages from dynamic cdn insertion
|
||||
scriptLoading: 'blocking',
|
||||
inject: 'body',
|
||||
}),
|
||||
new HtmlWebpackInlineSourcePlugin(),
|
||||
new DynamicCdnWebpackPlugin({}),
|
||||
@@ -290,6 +306,7 @@ const serverConfig = {
|
||||
filename: 'code.js',
|
||||
path: destination,
|
||||
libraryTarget: 'this',
|
||||
publicPath,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js', '.json'],
|
||||
@@ -322,7 +339,6 @@ const serverConfig = {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
sourceMap: true,
|
||||
terserOptions: {
|
||||
// ecma 5 is needed to support Rhino "DEPRECATED_ES5" runtime
|
||||
// can use ecma 6 if V8 runtime is used
|
||||
@@ -345,13 +361,6 @@ const serverConfig = {
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
// replace any env variables in client-side code like PORT and NODE_ENV with actual values
|
||||
'process.env': JSON.stringify(envVars),
|
||||
'process.env.NODE_ENV': JSON.stringify(
|
||||
isProd ? 'production' : 'development'
|
||||
),
|
||||
}),
|
||||
new GasPlugin({
|
||||
// removes need for assigning public server functions to "global"
|
||||
autoGlobalExportsFiles: [serverEntry],
|
||||
|
||||