From 49d343941e236e442114e59861a373c7edb0b1fb Mon Sep 17 00:00:00 2001 From: Danny Brown Date: Wed, 4 Sep 2019 13:53:13 -0400 Subject: [PATCH] fix: measurementsAPI issue caused by production build (#842) * ci: test docs-publish * Specify to use prod * Babel should transpile with env set by webpack * in-progress * in-progress * Polyfill for ie11 and edge features * Ditch polyfills w/ babel - we'll use a service for now * Bump tools version; shift vtk.js up a layer * Specify we shouldn't target older than IE 11 * ditch babel plugins that should be covered by preset-env * Add a top level build demo command * Let our babel config determine settings * Same babel fixes as PWA * Rebuild deps that don't satisfy our target * Mini helper script for excluding all node_modules, except... * Shift vtk.js dep up a layer * Kill core-js * Export in a node happy way * Updated yarn lock * Set NODE_ENV when launching anything w/ WebPack * docs: updated FAQ * docs: on browser support * Add support for redux browser extension * misc. small clean-up * docs: Remove roadmap page; add browser-support to sidebar * Formatting * Remove roadmap links * Formatting * ci: Remove config syntax error * Simplified bug report template * update community request template * Update question's template * simplify build scripts * specify new script names * fix: for measurement api being pruned by minimizer in prod builds * Use named exports * Simplify config * Let's not do so much heavy lifting for a dev-server build * fix dev build * Add hotkeys to demo * fix: jest babel config and env specific configs * Remove call to non-existant command * Shift experimental proposal plugin up a layer * Use `https` * Try with reduced number of package exceptions * Try to resolve cypress issue * Try to fix cypress issue in CI * Skip https --- .browserslistrc | 6 + .circleci/config.yml | 6 +- .github/ISSUE_TEMPLATE/---bug-report.md | 36 +- .github/ISSUE_TEMPLATE/---feature-request.md | 22 +- .github/ISSUE_TEMPLATE/---support-question.md | 8 +- .webpack/helpers/excludeNodeModulesExcept.js | 22 + .webpack/rules/cssToJavaScript.js | 17 + .webpack/rules/loadShaders.js | 10 + .webpack/rules/loadWebWorkers.js | 17 + .webpack/rules/stylusToJavaScript.js | 10 + .webpack/rules/transpileJavaScript.js | 39 + .webpack/webpack.base.js | 56 + .webpack/webpack.common-pwa.js | 101 -- .webpack/webpack.common.js | 131 --- .webpack/webpack.commonjs.js | 18 + babel.config.js | 98 +- docs/latest/SUMMARY.md | 4 +- docs/latest/browser-support.md | 47 + .../google-cloud-healthcare.md | 16 +- docs/latest/essentials/getting-started.md | 4 +- docs/latest/frequently-asked-questions.md | 84 +- docs/latest/roadmap.md | 25 - docs/v1/faq/general.md | 80 +- .../cornerstone/.webpack/webpack.dev.js | 12 +- .../cornerstone/.webpack/webpack.prod.js | 4 +- extensions/dicom-html/.webpack/webpack.dev.js | 12 +- .../dicom-html/.webpack/webpack.prod.js | 4 +- .../dicom-microscopy/.webpack/webpack.dev.js | 12 +- .../dicom-microscopy/.webpack/webpack.prod.js | 4 +- extensions/dicom-pdf/.webpack/webpack.dev.js | 12 +- extensions/dicom-pdf/.webpack/webpack.prod.js | 4 +- extensions/vtk/.webpack/webpack.dev.js | 12 +- extensions/vtk/.webpack/webpack.prod.js | 4 +- extensions/vtk/package.json | 3 +- .../vtk/src/utils/setLayoutAndViewportData.js | 2 +- maintainer-notes.md | 20 - package.json | 16 +- platform/core/.webpack/webpack.dev.js | 8 + platform/core/.webpack/webpack.prod.js | 4 +- .../measurements/classes/MeasurementApi.js | 3 +- .../src/measurements/classes/TimepointApi.js | 5 +- .../core/src/measurements/configuration.js | 11 +- platform/core/src/measurements/index.js | 3 - platform/i18n/.webpack/webpack.dev.js | 12 +- platform/i18n/.webpack/webpack.prod.js | 4 +- platform/ui/.webpack/webpack.prod.js | 4 +- platform/viewer/.browserslistrc | 7 + platform/viewer/.webpack/all.dev.js | 74 -- .../.webpack/rules/extractStyleChunks.js | 35 + .../.webpack/rules/fontsToJavaScript.js | 20 + .../{commonjs.prod.js => webpack.commonjs.js} | 27 +- .../.webpack/{pwa.prod.js => webpack.pwa.js} | 148 +-- platform/viewer/README.md | 35 +- platform/viewer/package.json | 23 +- platform/viewer/public/config/demo.js | 49 +- .../viewer/public/html-templates/index.html | 3 + .../viewer/public/html-templates/rollbar.html | 3 + platform/viewer/server.js | 1024 +++++++++++++++++ platform/viewer/src/App.js | 6 - platform/viewer/src/index.js | 3 + platform/viewer/src/store/index.js | 9 +- postcss.config.js | 20 +- yarn.lock | 74 +- 63 files changed, 1776 insertions(+), 816 deletions(-) create mode 100644 .browserslistrc create mode 100644 .webpack/helpers/excludeNodeModulesExcept.js create mode 100644 .webpack/rules/cssToJavaScript.js create mode 100644 .webpack/rules/loadShaders.js create mode 100644 .webpack/rules/loadWebWorkers.js create mode 100644 .webpack/rules/stylusToJavaScript.js create mode 100644 .webpack/rules/transpileJavaScript.js create mode 100644 .webpack/webpack.base.js delete mode 100644 .webpack/webpack.common-pwa.js delete mode 100644 .webpack/webpack.common.js create mode 100644 .webpack/webpack.commonjs.js create mode 100644 docs/latest/browser-support.md delete mode 100644 docs/latest/roadmap.md create mode 100644 platform/core/.webpack/webpack.dev.js create mode 100644 platform/viewer/.browserslistrc delete mode 100644 platform/viewer/.webpack/all.dev.js create mode 100644 platform/viewer/.webpack/rules/extractStyleChunks.js create mode 100644 platform/viewer/.webpack/rules/fontsToJavaScript.js rename platform/viewer/.webpack/{commonjs.prod.js => webpack.commonjs.js} (59%) rename platform/viewer/.webpack/{pwa.prod.js => webpack.pwa.js} (52%) create mode 100644 platform/viewer/server.js diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 00000000000..d10bb62c105 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,6 @@ +# Browsers that we support + +> 1% +IE 11 +not dead +not op_mini all diff --git a/.circleci/config.yml b/.circleci/config.yml index 2d4ee5c2b99..9aec66e23fd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -279,7 +279,8 @@ workflows: # Cypress job added by `cypress-io` orb - cypress/run: pre-steps: - - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v' # Use yarn latest + - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global + add wait-on' # Use yarn latest yarn: true store_artifacts: true start: yarn run dev @@ -303,7 +304,8 @@ workflows: # Cypress job added by `cypress-io` orb - cypress/run: pre-steps: - - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v' # Use yarn latest + - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global + add wait-on' # Use yarn latest yarn: true record: true store_artifacts: true diff --git a/.github/ISSUE_TEMPLATE/---bug-report.md b/.github/ISSUE_TEMPLATE/---bug-report.md index b4193c51370..29d71003949 100644 --- a/.github/ISSUE_TEMPLATE/---bug-report.md +++ b/.github/ISSUE_TEMPLATE/---bug-report.md @@ -2,38 +2,32 @@ name: "\U0001F41B Bug report" about: Create a report to help us improve title: '' -labels: 'Bug Report :bug:' +labels: 'Community: Report :bug:' assignees: '' --- -**Before Creating an issue** +> **Before Creating an issue** +> +> - Are you running the latest version? +> - Are you reporting to the correct repository? +> - Did you search existing issues? -- Are you running the latest version? -- Are you reporting to the correct repository? -- Did you search existing issues? +## Bug Report -**Describe the bug** +### Describe the Bug _A clear and concise description of what the bug is._ -**Steps To Reproduce** +### What steps can we follow to reproduce the bug? -1. [First Step] -2. [Second Step] +1. First step +2. Second step 3. ... -``` +```js Please use code blocks to show formatted errors or code snippets ``` -**Expected behavior** - -_A clear and concise description of what you expected to happen._ - -**Environment** - -- OS: [e.g. iOS] -- Browser [e.g. chrome, safari] -- Version [e.g. 22] - -**Additional context** +> :warning: Reports we cannot reproduce are at risk of being marked stale and +> closed. The more information you can provide, the more likely we are to look +> into and address your issue. diff --git a/.github/ISSUE_TEMPLATE/---feature-request.md b/.github/ISSUE_TEMPLATE/---feature-request.md index 35159e5d5d8..def985ac074 100644 --- a/.github/ISSUE_TEMPLATE/---feature-request.md +++ b/.github/ISSUE_TEMPLATE/---feature-request.md @@ -2,18 +2,24 @@ name: "\U0001F680 Feature request" about: Suggest an idea for this project title: '' -labels: enhancement +labels: 'Community: Request :hand:' assignees: '' --- - +## Request - +... -Please include the reasons why you think your change should be made, and any -supporting evidence that helps us asses its value and priority. +**Why should we prioritize this feature?** + +... diff --git a/.github/ISSUE_TEMPLATE/---support-question.md b/.github/ISSUE_TEMPLATE/---support-question.md index 72e14e429b7..db919cc40ae 100644 --- a/.github/ISSUE_TEMPLATE/---support-question.md +++ b/.github/ISSUE_TEMPLATE/---support-question.md @@ -2,13 +2,13 @@ name: "\U0001F917 Support Question" about: "I have a question \U0001F4AC" title: '' -labels: question +labels: 'Community: Question :question:' assignees: '' --- -We are a small team with limited resources. Your question is much more likely to -be answered if it is -[a good question](https://stackoverflow.com/help/how-to-ask) +> :hand: We are a small team with limited resources. Your question is much more +> likely to be answered if it is +> [a good question](https://stackoverflow.com/help/how-to-ask) **Description** diff --git a/.webpack/helpers/excludeNodeModulesExcept.js b/.webpack/helpers/excludeNodeModulesExcept.js new file mode 100644 index 00000000000..f7234de1a24 --- /dev/null +++ b/.webpack/helpers/excludeNodeModulesExcept.js @@ -0,0 +1,22 @@ +const path = require('path'); + +function excludeNodeModulesExcept(modules) { + var pathSep = path.sep; + if (pathSep == '\\') + // must be quoted for use in a regexp: + pathSep = '\\\\'; + var moduleRegExps = modules.map(function(modName) { + return new RegExp('node_modules' + pathSep + modName); + }); + + return function(modulePath) { + if (/node_modules/.test(modulePath)) { + for (var i = 0; i < moduleRegExps.length; i++) + if (moduleRegExps[i].test(modulePath)) return false; + return true; + } + return false; + }; +} + +module.exports = excludeNodeModulesExcept; diff --git a/.webpack/rules/cssToJavaScript.js b/.webpack/rules/cssToJavaScript.js new file mode 100644 index 00000000000..5d4d55d3323 --- /dev/null +++ b/.webpack/rules/cssToJavaScript.js @@ -0,0 +1,17 @@ +const autoprefixer = require('autoprefixer'); + +const cssToJavaScript = { + test: /\.css$/, + use: [ + 'style-loader', + { loader: 'css-loader', options: { importLoaders: 1 } }, + { + loader: 'postcss-loader', + options: { + plugins: () => [autoprefixer('last 2 version', 'ie >= 11')], + }, + }, + ], +}; + +module.exports = cssToJavaScript; diff --git a/.webpack/rules/loadShaders.js b/.webpack/rules/loadShaders.js new file mode 100644 index 00000000000..49dbef5f998 --- /dev/null +++ b/.webpack/rules/loadShaders.js @@ -0,0 +1,10 @@ +/** + * This is exclusively used by `vtk.js` to bundle glsl files. + */ +const loadShaders = { + test: /\.glsl$/i, + include: /vtk\.js[\/\\]Sources/, + loader: 'shader-loader', +}; + +module.exports = loadShaders; diff --git a/.webpack/rules/loadWebWorkers.js b/.webpack/rules/loadWebWorkers.js new file mode 100644 index 00000000000..a4ab2841590 --- /dev/null +++ b/.webpack/rules/loadWebWorkers.js @@ -0,0 +1,17 @@ +/** + * This allows us to include web workers in our bundle, and VTK.js + * web workers in our bundle. While this increases bundle size, it + * cuts down on the number of includes we need for `script tag` usage. + */ +const loadWebWorkers = { + test: /\.worker\.js$/, + include: /vtk\.js[\/\\]Sources/, + use: [ + { + loader: 'worker-loader', + options: { inline: true, fallback: false }, + }, + ], +}; + +module.exports = loadWebWorkers; diff --git a/.webpack/rules/stylusToJavaScript.js b/.webpack/rules/stylusToJavaScript.js new file mode 100644 index 00000000000..1d83f95281e --- /dev/null +++ b/.webpack/rules/stylusToJavaScript.js @@ -0,0 +1,10 @@ +const stylusToJavaScript = { + test: /\.styl$/, + use: [ + { loader: 'style-loader' }, // 3. Style nodes from JS Strings + { loader: 'css-loader' }, // 2. CSS to CommonJS + { loader: 'stylus-loader' }, // 1. Stylus to CSS + ], +}; + +module.exports = stylusToJavaScript; diff --git a/.webpack/rules/transpileJavaScript.js b/.webpack/rules/transpileJavaScript.js new file mode 100644 index 00000000000..723a6e32136 --- /dev/null +++ b/.webpack/rules/transpileJavaScript.js @@ -0,0 +1,39 @@ +const excludeNodeModulesExcept = require('./../helpers/excludeNodeModulesExcept.js'); + +function transpileJavaScript(mode) { + const exclude = + mode === 'production' + ? excludeNodeModulesExcept([ + 'vtk.js', + // 'dicomweb-client', + // https://github.com/react-dnd/react-dnd/blob/master/babel.config.js + 'react-dnd', + // https://github.com/dcmjs-org/dcmjs/blob/master/.babelrc + // https://github.com/react-dnd/react-dnd/issues/1342 + // 'dcmjs', // contains: loglevelnext + // https://github.com/shellscape/loglevelnext#browser-support + // 'loglevelnext', + // https://github.com/dcmjs-org/dicom-microscopy-viewer/issues/35 + // 'dicom-microscopy-viewer', + // https://github.com/openlayers/openlayers#supported-browsers + // 'ol', --> Should be fine + ]) + : excludeNodeModulesExcept([]); + + return { + test: /\.jsx?$/, + // These are packages that are not transpiled to our lowest supported + // JS version (currently ES5). Most of these leverage ES6+ features, + // that we need to transpile to a different syntax. + exclude, + loader: 'babel-loader', + options: { + // Find babel.config.js in monorepo root + // https://babeljs.io/docs/en/options#rootmode + rootMode: 'upward', + envName: mode, + }, + }; +} + +module.exports = transpileJavaScript; diff --git a/.webpack/webpack.base.js b/.webpack/webpack.base.js new file mode 100644 index 00000000000..056ea959612 --- /dev/null +++ b/.webpack/webpack.base.js @@ -0,0 +1,56 @@ +const path = require('path'); +const webpack = require('webpack'); +const loadShadersRule = require('./rules/loadShaders.js'); +const loadWebWorkersRule = require('./rules/loadWebWorkers.js'); +const transpileJavaScriptRule = require('./rules/transpileJavaScript.js'); + +module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => { + if (!process.env.NODE_ENV) { + throw new Error('process.env.NODE_ENV not set'); + } + + const mode = + process.env.NODE_ENV === 'production' ? 'production' : 'development'; + + return { + mode, + entry: { + app: `${SRC_DIR}/index.js`, + }, + context: SRC_DIR, + module: { + rules: [ + transpileJavaScriptRule(mode), + loadWebWorkersRule, + loadShadersRule, + ], + }, + resolve: { + // Which directories to search when resolving modules + modules: [ + // Modules specific to this package + path.resolve(__dirname, '../node_modules'), + // Hoisted Yarn Workspace Modules + path.resolve(__dirname, '../../../node_modules'), + SRC_DIR, + ], + // Attempt to resolve these extensions in order. + extensions: ['.js', '.jsx', '.json', '*'], + // symlinked resources are resolved to their real path, not their symlinked location + symlinks: true, + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), + 'process.env.DEBUG': JSON.stringify(process.env.DEBUG), + 'process.env.APP_CONFIG': JSON.stringify(process.env.APP_CONFIG || ''), + 'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL || '/'), + }), + ], + // Fix: https://github.com/webpack-contrib/css-loader/issues/447#issuecomment-285598881 + // For issue in cornerstone-wado-image-loader + node: { + fs: 'empty', + }, + }; +}; diff --git a/.webpack/webpack.common-pwa.js b/.webpack/webpack.common-pwa.js deleted file mode 100644 index e452003ae21..00000000000 --- a/.webpack/webpack.common-pwa.js +++ /dev/null @@ -1,101 +0,0 @@ -const path = require('path'); -const webpack = require('webpack'); -const autoprefixer = require('autoprefixer'); - -module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => { - const mode = - process.env.NODE_ENV === 'production' ? 'production' : 'development'; - - return { - mode, - entry: { - bundle: `${SRC_DIR}/index.js`, - }, - context: SRC_DIR, - module: { - rules: [ - /** - * JSX - */ - { - test: /\.jsx?$/, - exclude: [/node_modules/, /packages\\extension/], - loader: 'babel-loader', - options: { - // Find babel.config.js in monorepo root - // https://babeljs.io/docs/en/options#rootmode - rootMode: 'upward', - envName: mode, - presets: [ - [ - '@babel/preset-env', - { - // Do not transform ES6 modules to another format. - // Webpack will take care of that. - modules: false, - targets: { - ie: '11', - }, - // https://babeljs.io/docs/en/babel-preset-env#usebuiltins - useBuiltIns: 'usage', - // https://babeljs.io/docs/en/babel-preset-env#corejs - corejs: 3, - }, - ], - ], - }, - }, - /** - * This allows us to include web workers in our bundle, and VTK.js - * web workers in our bundle. While this increases bundle size, it - * cuts down on the number of includes we need for `script tag` usage. - */ - { - test: /\.worker\.js$/, - include: /vtk\.js[\/\\]Sources/, - use: [ - { - loader: 'worker-loader', - options: { inline: true, fallback: false }, - }, - ], - }, - /** - * This is exclusively used by `vtk.js` to bundle glsl files. - */ - { - test: /\.glsl$/i, - include: /vtk\.js[\/\\]Sources/, - loader: 'shader-loader', - }, - ], - }, - resolve: { - // Which directories to search when resolving modules - modules: [ - // Modules specific to this package - path.resolve(__dirname, '../node_modules'), - // Hoisted Yarn Workspace Modules - path.resolve(__dirname, '../../../node_modules'), - SRC_DIR, - ], - // Attempt to resolve these extensions in order. - extensions: ['.js', '.jsx', '.json', '*'], - // symlinked resources are resolved to their real path, not their symlinked location - symlinks: true, - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), - 'process.env.DEBUG': JSON.stringify(process.env.DEBUG), - 'process.env.APP_CONFIG': JSON.stringify(process.env.APP_CONFIG || ''), - 'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL || '/'), - }), - ], - // Fix: https://github.com/webpack-contrib/css-loader/issues/447#issuecomment-285598881 - // For issue in cornerstone-wado-image-loader - node: { - fs: 'empty', - }, - }; -}; diff --git a/.webpack/webpack.common.js b/.webpack/webpack.common.js deleted file mode 100644 index 4d8b89cfc92..00000000000 --- a/.webpack/webpack.common.js +++ /dev/null @@ -1,131 +0,0 @@ -const path = require('path'); -const webpack = require('webpack'); -const autoprefixer = require('autoprefixer'); - -module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => { - const mode = - process.env.NODE_ENV === 'production' ? 'production' : 'development'; - - return { - mode, - entry: { - bundle: `${SRC_DIR}/index.js`, - }, - context: SRC_DIR, - module: { - rules: [ - /** - * JSX - */ - { - test: /\.jsx?$/, - exclude: [/node_modules/, /packages\\extension/], - loader: 'babel-loader', - options: { - // Find babel.config.js in monorepo root - // https://babeljs.io/docs/en/options#rootmode - rootMode: 'upward', - envName: mode, - presets: [ - [ - '@babel/preset-env', - { - // Do not transform ES6 modules to another format. - // Webpack will take care of that. - modules: false, - targets: { - ie: '11', - }, - // https://babeljs.io/docs/en/babel-preset-env#usebuiltins - useBuiltIns: 'usage', - // https://babeljs.io/docs/en/babel-preset-env#corejs - corejs: 3, - }, - ], - ], - }, - }, - /** - * Stylus to CSS - * CSS to CommonJS - * Style nodes from JS Strings - */ - { - test: /\.styl$/, - use: [ - { loader: 'style-loader' }, - { loader: 'css-loader' }, - { loader: 'stylus-loader' }, - ], - }, - { - test: /\.css$/, - use: [ - 'style-loader', - // ExtractCssChunks.loader, - { loader: 'css-loader', options: { importLoaders: 1 } }, - { - loader: 'postcss-loader', - options: { - config: { - path: './postcss.config.js', - }, - plugins: () => [autoprefixer('last 2 version', 'ie >= 11')], - }, - }, - ], - }, - /** - * This allows us to include web workers in our bundle, and VTK.js - * web workers in our bundle. While this increases bundle size, it - * cuts down on the number of includes we need for `script tag` usage. - */ - { - test: /\.worker\.js$/, - include: /vtk\.js[\/\\]Sources/, - use: [ - { - loader: 'worker-loader', - options: { inline: true, fallback: false }, - }, - ], - }, - /** - * This is exclusively used by `vtk.js` to bundle glsl files. - */ - { - test: /\.glsl$/i, - include: /vtk\.js[\/\\]Sources/, - loader: 'shader-loader', - }, - ], - }, - resolve: { - // Which directories to search when resolving modules - modules: [ - // Modules specific to this package - path.resolve(__dirname, '../node_modules'), - // Hoisted Yarn Workspace Modules - path.resolve(__dirname, '../../../node_modules'), - SRC_DIR, - ], - // Attempt to resolve these extensions in order. - extensions: ['.js', '.jsx', '.json', '*'], - // symlinked resources are resolved to their real path, not their symlinked location - symlinks: true, - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), - 'process.env.DEBUG': JSON.stringify(process.env.DEBUG), - 'process.env.APP_CONFIG': JSON.stringify(process.env.APP_CONFIG || ''), - 'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL || '/'), - }), - ], - // Fix: https://github.com/webpack-contrib/css-loader/issues/447#issuecomment-285598881 - // For issue in cornerstone-wado-image-loader - node: { - fs: 'empty', - }, - }; -}; diff --git a/.webpack/webpack.commonjs.js b/.webpack/webpack.commonjs.js new file mode 100644 index 00000000000..e531b18de0c --- /dev/null +++ b/.webpack/webpack.commonjs.js @@ -0,0 +1,18 @@ +const webpackBase = require('./webpack.base.js'); +const cssToJavaScriptRule = require('./rules/cssToJavaScript.js'); +const stylusToJavaScriptRule = require('./rules/stylusToJavaScript.js'); + +/** + * WebPack configuration for CommonJS Bundles. Extends rules of BaseConfig by making + * sure we're bundling styles and other files that would normally be split in a + * PWA. + */ +module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => { + const baseConfig = webpackBase(env, argv, { SRC_DIR, DIST_DIR }); + + return merge(baseConfig, { + module: { + rules: [cssToJavaScriptRule, stylusToJavaScriptRule], + }, + }); +}; diff --git a/babel.config.js b/babel.config.js index 204019d22fb..8e0a57965fb 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,57 +1,63 @@ const aliases = require('./aliases.config'); const path = require('path'); +// https://babeljs.io/docs/en/options#babelrcroots module.exports = { - // Also specified in .webpack/webpack.common.js - // https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md - presets: [ - [ - '@babel/preset-env', - { - targets: { - ie: '11', - }, - // https://babeljs.io/docs/en/babel-preset-env#usebuiltins - useBuiltIns: 'usage', - // https://babeljs.io/docs/en/babel-preset-env#corejs - corejs: 3, - }, - ], - '@babel/preset-react', - ], - // https://babeljs.io/docs/en/options#babelrcroots babelrcRoots: ['./platform/*', './extensions/*'], - plugins: [ - 'react-hot-loader/babel', - 'inline-react-svg', - '@babel/plugin-proposal-class-properties', - '@babel/plugin-proposal-object-rest-spread', - '@babel/plugin-syntax-dynamic-import', - '@babel/plugin-transform-regenerator', - '@babel/plugin-transform-runtime', - [ - 'module-resolver', - { - // https://github.com/tleunen/babel-plugin-module-resolver/issues/338 - // There seem to be a bug with module-resolver with a mono-repo setup: - // It doesn't resolve paths correctly when using root/alias combo, so we - // use this function instead. - resolvePath(sourcePath, currentFile, opts) { - // This will return undefined if aliases has no key for the sourcePath, - // in which case module-resolver will fallback on its default behaviour. - return aliases[sourcePath]; - }, - }, - ], - ], + plugins: ['inline-react-svg', '@babel/plugin-proposal-class-properties'], env: { - debug: { - sourceMaps: 'inline', - retainLines: true, + test: { + presets: [ + [ + // TODO: https://babeljs.io/blog/2019/03/19/7.4.0#migration-from-core-js-2 + '@babel/preset-env', + { + modules: 'commonjs', + debug: false, + }, + ], + '@babel/preset-react', + ], + plugins: [ + '@babel/plugin-proposal-object-rest-spread', + '@babel/plugin-syntax-dynamic-import', + '@babel/plugin-transform-regenerator', + '@babel/plugin-transform-runtime', + ], }, - build: { + production: { + presets: [ + // WebPack handles ES6 --> Target Syntax + ['@babel/preset-env', { modules: false }], + '@babel/preset-react', + ], + ignore: ['**/*.test.jsx', '**/*.test.js', '__snapshots__', '__tests__'], + }, + development: { + presets: [ + // WebPack handles ES6 --> Target Syntax + ['@babel/preset-env', { modules: false }], + '@babel/preset-react', + ], + plugins: ['react-hot-loader/babel'], ignore: ['**/*.test.jsx', '**/*.test.js', '__snapshots__', '__tests__'], }, }, - // ignore: ["node_modules"] }; + +// TODO: Plugins; Aliases +// We don't currently use aliases, but this is a nice snippet that would help +// [ +// 'module-resolver', +// { +// // https://github.com/tleunen/babel-plugin-module-resolver/issues/338 +// // There seem to be a bug with module-resolver with a mono-repo setup: +// // It doesn't resolve paths correctly when using root/alias combo, so we +// // use this function instead. +// resolvePath(sourcePath, currentFile, opts) { +// // This will return undefined if aliases has no key for the sourcePath, +// // in which case module-resolver will fallback on its default behaviour. +// return aliases[sourcePath]; +// }, +// }, +// ], diff --git a/docs/latest/SUMMARY.md b/docs/latest/SUMMARY.md index 568440aa693..5c4f55ed609 100644 --- a/docs/latest/SUMMARY.md +++ b/docs/latest/SUMMARY.md @@ -45,7 +45,7 @@ --- -- [Contributing](contributing.md) - [FAQ](frequently-asked-questions.md) -- [Roadmap](roadmap.md) +- [Contributing](contributing.md) +- [Browser Support](browser-support.md) - [Help](help.md) diff --git a/docs/latest/browser-support.md b/docs/latest/browser-support.md new file mode 100644 index 00000000000..d5f1a1cf329 --- /dev/null +++ b/docs/latest/browser-support.md @@ -0,0 +1,47 @@ +# Browser Support + +The browsers that we support are specified in the `.browserlistrc` file located +in the `platform/viewer` project. While we leverage the latest language features +when writing code, we rely on `babel` to _transpile_ our code so that it can run +in the browsers that we support. + +## In Practice + +The OHIF Viewer is capable of _running_ on: + +- IE 11 +- FireFox +- Chrome +- Safari +- Edge + +However, we do not have the resources to adequately test and maintain bug free +functionality across all of these. In order to push web based medical imaging +forward, we focus our development efforts on recent version of modern evergreen +browsers. + +Our support of older browsers equates to our willingness to review PRs for bug +fixes, and target their minimum JS support whenever possible. + +### Polyfills + +> A polyfill, or polyfiller, is a piece of code (or plugin) that provides the +> technology that you, the developer, expect the browser to provide natively. + +An example of a polyfill is that you expect `Array.prototype.filter` to exist, +but for some reason, the browser that's being used has not implemented that +language feature yet. Our earlier transpilation will rectify _syntax_ +discrepencies, but unimplemented features require a "temporary" implementation. +That's where polyfills step in. + +You can utilize a service like [polyfill.io](https://polyfill.io/v3/) to +auto-detect and apply polyfills as needed, or you can update the PWA build to +include polyfill's in your bundle by incorporating [core-js][core-js] + + + + +[core-js]: https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md + diff --git a/docs/latest/connecting-to-image-archives/google-cloud-healthcare.md b/docs/latest/connecting-to-image-archives/google-cloud-healthcare.md index dc36b8e1d14..6fce2746b85 100644 --- a/docs/latest/connecting-to-image-archives/google-cloud-healthcare.md +++ b/docs/latest/connecting-to-image-archives/google-cloud-healthcare.md @@ -35,10 +35,10 @@ Images can even be transcoded on the fly if this is desired. - Choose the "Web Application" type - Set up an [OAuth 2.0 Client ID](https://support.google.com/cloud/answer/6158849?hl=en) - - Add your domain (e.g. `http://localhost:5000`) to Authorized JavaScript + - Add your domain (e.g. `http://localhost:3000`) to Authorized JavaScript origins. - - Add your domain, plus `callback` (e.g. - `http://localhost:5000/callback`) to Authorized Redirect URIs. + - Add your domain, plus `callback` (e.g. `http://localhost:3000/callback`) to + Authorized Redirect URIs. - Save your Client ID for later. - (Optional): Enable Public Datasets that are being hosted by Google: @@ -46,8 +46,8 @@ Images can even be transcoded on the fly if this is desired. ## Run the viewer with your OAuth Client ID -1. Open the `config/google.js` file and change `YOURCLIENTID` to - your Client ID value. +1. Open the `config/google.js` file and change `YOURCLIENTID` to your Client ID + value. 1. Run the OHIF Viewer using the config/google.js configuration file ```bash @@ -58,9 +58,9 @@ APP_CONFIG=config/google.js yarn run dev ## Running via Docker -The OHIF Viewer Docker container can be connected to Google Cloud -Healthcare by providing a Client ID at runtime. This is a very simple -method to get up and running. +The OHIF Viewer Docker container can be connected to Google Cloud Healthcare by +providing a Client ID at runtime. This is a very simple method to get up and +running. 1. Install Docker (https://www.docker.com/) 1. Run the Docker container, providing a Client ID as an environment variable. diff --git a/docs/latest/essentials/getting-started.md b/docs/latest/essentials/getting-started.md index f569429ca9d..6ade64f41b9 100644 --- a/docs/latest/essentials/getting-started.md +++ b/docs/latest/essentials/getting-started.md @@ -60,8 +60,8 @@ Compiled successfully! You can now view ohif-viewer in the browser. - Local: http://localhost:5000/ - On Your Network: http://10.74.20.83:5000/ + Local: http://localhost:3000/ + On Your Network: http://10.74.20.83:3000/ Note that the development build is not optimized. To create a production build, use yarn build. diff --git a/docs/latest/frequently-asked-questions.md b/docs/latest/frequently-asked-questions.md index 7dea3a284cd..eca28594cbe 100644 --- a/docs/latest/frequently-asked-questions.md +++ b/docs/latest/frequently-asked-questions.md @@ -1,36 +1,18 @@ # Frequently Asked Questions -## How do I file a bug? - -We accept and triage bug reports through Github primarily. - -- [Create a Github account](https://github.com/join) -- Search the current [Issue List](https://github.com/OHIF/Viewers/issues) to - ensure you are not creating a duplicate issue. - - If your issue already exists, post a comment to show us that this issue also - affects you. -- If no prior issue exists, - [Create a New Issue](https://github.com/OHIF/Viewers/issues/new) on the - repository. - -Some tips for filing a new issue: - -- **Make sure your issue is reproducible**: If we try to reproduce your issue - given your provided steps and we cannot reproduce it, we will not be able to - fix it. _Nobody wants to spend time guessing how to reproduce your issue!_ - Before filing, please reproduce your issue more than once and clearly describe - the steps taken. -- **If you are reporting a user interface issue, provide screenshots**: A - picture is worth a thousand words. If your issue concerns the UI, screenshots - will help us identify the issue dramatically faster since it can be extremely - challenging to describe UI bugs with text. _You should still clearly describe - the steps that you took to produce the issue_. -- **Include platform & environment**: Your operating system, web browser, and - web browser version are highly relevant for many bugs. Please provide these - with all bug reports. -- **Include expected and actual result**: Tell us what you expected to happen, - and what actually happened. If you don't do this, we might not consider it a - bug. +## Index + +- [Report a bug][report-bug] +- [Request a feature][new-feature] +- [Commercial Support & Consulting][commercial-support] +- [Academic collaborations][academic] +- [FDA Clearance or CE Marking][fda-clearance] +- [HIPAA Compliance][hipaa] + +### How do I report a bug? + +Navigate to our [GitHub Repository][new-issue], and submit a new bug report. +Follow the steps outlined in the [Bug Report Template][bug-report-template]. ### How can I request a new feature? @@ -39,7 +21,8 @@ to communicate this to the community. If your requested feature is on the roadmap, then it will most likely be built at some point. If it is not, you are welcome to build it yourself and [contribute it](contributing.md). If you have resources and would like to fund the development of a feature, please -[contact us](http://www.ohif.org). +[contact us](http://www.ohif.org) or work with community members that offer +[consulting services][commercial-support]. ### Who should I contact about Academic Collaborations? @@ -49,7 +32,7 @@ collaborators. We are always happy to hear about new groups interested in using the OHIF framework, and may be able to provide development support if the proposed collaboration has an impact on cancer research. -### Do you offer commercial support? +### Does OHIF offer commercial support? The Open Health Imaging Foundation does not offer commercial support, however, some community members do offer consulting services. The following contacts may @@ -60,36 +43,39 @@ be useful: **Please file a Pull Request if you wish to add your name or organization to this list.** -### I emailed my question to you directly and you did not respond. Why not? - -Emailing developers directly is not a shortcut to faster support. Please file -your issues and questions on Github so that everyone can benefit from the -discussion and solutions. - -### Do your Viewers have [510(k) Clearance][501k-clearance] from the U.S. F.D.A or [CE Marking][ce-marking] from the European Commission? +### Does The OHIF Viewer have [510(k) Clearance][501k-clearance] from the U.S. F.D.A or [CE Marking][ce-marking] from the European Commission? -**NO.** The OHIF Viewer, Lesion Tracker, and Standalone Viewer, **NOT** F.D.A. -cleared or CE Marked. It is the users responsibility to ensure compliance with -applicable rules and regulations. The +**NO.** The OHIF Viewer is **NOT** F.D.A. cleared or CE Marked. It is the users +responsibility to ensure compliance with applicable rules and regulations. The [License](https://github.com/OHIF/Viewers/blob/master/LICENSE) for the OHIF -Framework does not prevent your company or group from seeking F.D.A. clearance -for a product built using the framework. +Platform does not prevent your company or group from seeking F.D.A. clearance +for a product built using the platform. If you have gone this route (or are going there), please let us know because we would be interested to hear about your experience. -### Are your Viewers [HIPAA][hipaa] Compliant? +### Is The OHIF Viewer [HIPAA][hipaa] Compliant? -**NO.** The OHIF Viewer, Lesion Tracker, and Standalone Viewer **DO NOT** -fulfill all of the criteria to become HIPAA Compliant. It is the users -responsibility to ensure compliance with applicable rules and regulations. +**NO.** The OHIF Viewer **DOES NOT** fulfill all of the criteria to become HIPAA +Compliant. It is the users responsibility to ensure compliance with applicable +rules and regulations. + +[report-bug]: #how-do-i-report-a-bug +[new-feature]: #how-can-i-request-a-new-feature +[commercial-support]: #does-ohif-offer-commercial-support +[academic]: #who-should-i-contact-about-academic-collaborations +[fda-clearance]: #does-the-ohif-viewer-have-510k-clearance-from-the-us-fda-or-ce-marking-from-the-european-commission +[hipaa]: #is-the-ohif-viewer-hipaa-compliant + [501k-clearance]: https://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/HowtoMarketYourDevice/PremarketSubmissions/PremarketNotification510k/ [ce-marking]: https://ec.europa.eu/growth/single-market/ce-marking_en [hipaa]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act +[new-issue]: https://github.com/OHIF/Viewers/issues/new/choose +[bug-report-template]: https://github.com/OHIF/Viewers/issues/new?assignees=&labels=Bug+Report+%3Abug%3A&template=---bug-report.md&title= diff --git a/docs/latest/roadmap.md b/docs/latest/roadmap.md deleted file mode 100644 index d5e516a8701..00000000000 --- a/docs/latest/roadmap.md +++ /dev/null @@ -1,25 +0,0 @@ -# Roadmap - -If you want to know what's planned for the very near future, -[check out our roadmap](https://ohif.canny.io/). The best way to influence when -and what is worked on is to contribute to the conversation by creating GitHub -issues, and contributing code through pull requests. OHIF's high level -priorities for the near future are: - -- Feature parity with version 1 -- Extension and configuration improvements with key integration partners -- Continued Developer Experience Improvements -- Segmentation Tools, and improved VTK.js support - -More granular information will make it's way to the backlog as these items -become scoped for development by core maintainers. - -> Don't hesitate to ask questions, propose features, or create pull requests. -> We're here, we're listening, and we're ready to build the best open source -> medical imaging viewer on the web. - -### Roadmap Generously Powered by Canny.io - - - - diff --git a/docs/v1/faq/general.md b/docs/v1/faq/general.md index 853e8c7facf..ed96d465d51 100644 --- a/docs/v1/faq/general.md +++ b/docs/v1/faq/general.md @@ -1,47 +1,93 @@ # Frequently Asked Questions - General + ### How do I file a bug? + We accept and triage bug reports through Github primarily. + 1. [Create a Github account](https://github.com/join) -2. Search the current [Issue List](https://github.com/OHIF/Viewers/issues) to ensure you are not creating a duplicate issue. +2. Search the current [Issue List](https://github.com/OHIF/Viewers/issues) to + ensure you are not creating a duplicate issue. - If your issue already exists, post a comment to show us that this issue also affects you. +If your issue already exists, post a comment to show us that this issue also +affects you. -3. If no prior issue exists, [Create a New Issue](https://github.com/OHIF/Viewers/issues/new) on the repository. +3. If no prior issue exists, + [Create a New Issue](https://github.com/OHIF/Viewers/issues/new) on the + repository. Some tips for filing a new issue: -* **Make sure your issue is reproducible**: If we try to reproduce your issue given your provided steps and we cannot reproduce it, we will not be able to fix it. *Nobody wants to spend time guessing how to reproduce your issue!* Before filing, please reproduce your issue more than once and clearly describe the steps taken. -* **If you are reporting a user interface issue, provide screenshots**: A picture is worth a thousand words. If your issue concerns the UI, screenshots will help us identify the issue dramatically faster since it can be extremely challenging to describe UI bugs with text. *You should still clearly describe the steps that you took to produce the issue*. -* **Include platform & environment**: Your operating system, web browser, and web browser version are highly relevant for many bugs. Please provide these with all bug reports. -* **Include expected and actual result**: Tell us what you expected to happen, and what actually happened. If you don't do this, we might not consider it a bug. + +- **Make sure your issue is reproducible**: If we try to reproduce your issue + given your provided steps and we cannot reproduce it, we will not be able to + fix it. _Nobody wants to spend time guessing how to reproduce your issue!_ + Before filing, please reproduce your issue more than once and clearly describe + the steps taken. +- **If you are reporting a user interface issue, provide screenshots**: A + picture is worth a thousand words. If your issue concerns the UI, screenshots + will help us identify the issue dramatically faster since it can be extremely + challenging to describe UI bugs with text. _You should still clearly describe + the steps that you took to produce the issue_. +- **Include platform & environment**: Your operating system, web browser, and + web browser version are highly relevant for many bugs. Please provide these + with all bug reports. +- **Include expected and actual result**: Tell us what you expected to happen, + and what actually happened. If you don't do this, we might not consider it a + bug. ### How can I request a new feature? -At the moment we are in the process of defining our roadmap and will do our best to communicate this to the community. If your requested feature is on the roadmap, then it will most likely be built at some point. If it is not, you are welcome to build it yourself and [contribute it](../contributing.md). If you have resources and would like to fund the development of a feature, please [contact us](http://www.ohif.org). +At the moment we are in the process of defining our roadmap and will do our best +to communicate this to the community. If your requested feature is on the +roadmap, then it will most likely be built at some point. If it is not, you are +welcome to build it yourself and [contribute it](../contributing.md). If you +have resources and would like to fund the development of a feature, please +[contact us](http://www.ohif.org). ### Who should I contact about Academic Collaborations? -[Gordon J. Harris](http://www.dfhcc.harvard.edu/insider/member-detail/member/gordon-j-harris-phd/) at Massachusetts General Hospital is the primary contact for any academic collaborators. We are always happy to hear about new groups interested in using the OHIF framework, and may be able to provide development support if the proposed collaboration has an impact on cancer research. +[Gordon J. Harris](http://www.dfhcc.harvard.edu/insider/member-detail/member/gordon-j-harris-phd/) +at Massachusetts General Hospital is the primary contact for any academic +collaborators. We are always happy to hear about new groups interested in using +the OHIF framework, and may be able to provide development support if the +proposed collaboration has an impact on cancer research. ### Do you offer commercial support? -The Open Health Imaging Foundation does not offer commercial support, however, some community members do offer consulting services. The following contacts may be useful: +The Open Health Imaging Foundation does not offer commercial support, however, +some community members do offer consulting services. The following contacts may +be useful: -* Rob Lewis ([Radical Imaging](http://radicalimaging.com/)) +- Rob Lewis ([Radical Imaging](http://radicalimaging.com/)) -**Please file a Pull Request if you wish to add your name or organization to this list.** +**Please file a Pull Request if you wish to add your name or organization to +this list.** ### I emailed my question to you directly and you did not respond. Why not? -Emailing developers directly is not a shortcut to faster support. Please file your issues and questions on Github so that everyone can benefit from the discussion and solutions. +Emailing developers directly is not a shortcut to faster support. Please file +your issues and questions on Github so that everyone can benefit from the +discussion and solutions. ### Do your Viewers have [510(k) Clearance](https://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/HowtoMarketYourDevice/PremarketSubmissions/PremarketNotification510k/) from the U.S. F.D.A or [CE Marking](https://ec.europa.eu/growth/single-market/ce-marking_en) from the European Commission? -**NO.** The OHIF Viewer, Lesion Tracker, and Standalone Viewer, **NOT** F.D.A. cleared or CE Marked. It is the users responsibility to ensure compliance with applicable rules and regulations. The [License](https://github.com/OHIF/Viewers/blob/master/LICENSE) for the OHIF Framework does not prevent your company or group from seeking F.D.A. clearance for a product built using the framework. +**NO.** The OHIF Viewer, Lesion Tracker, and Standalone Viewer, **NOT** F.D.A. +cleared or CE Marked. It is the users responsibility to ensure compliance with +applicable rules and regulations. The +[License](https://github.com/OHIF/Viewers/blob/master/LICENSE) for the OHIF +Framework does not prevent your company or group from seeking F.D.A. clearance +for a product built using the framework. -If you have gone this route (or are going there), please let us know because we would be interested to hear about your experience. +If you have gone this route (or are going there), please let us know because we +would be interested to hear about your experience. ### Are your Viewers [HIPAA](https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act) Compliant? -**NO.** The OHIF Viewer, Lesion Tracker, and Standalone Viewer **DO NOT** fulfill all of the criteria to become HIPAA Compliant. It is the users responsibility to ensure compliance with applicable rules and regulations. +**NO.** The OHIF Viewer, Lesion Tracker, and Standalone Viewer **DO NOT** +fulfill all of the criteria to become HIPAA Compliant. It is the users +responsibility to ensure compliance with applicable rules and regulations. -The Lesion Tracker application demonstrates some available components and features (e.g. [Audit Trail](../lesion-tracker/audit-trail.md), automatic logoff, and unique user identification for [User Accounts](../lesion-tracker/user-accounts.md)) which could be used by third parties seeking HIPAA compliance. +The Lesion Tracker application demonstrates some available components and +features (e.g. [Audit Trail](../lesion-tracker/audit-trail.md), automatic +logoff, and unique user identification for +[User Accounts](../lesion-tracker/user-accounts.md)) which could be used by +third parties seeking HIPAA compliance. diff --git a/extensions/cornerstone/.webpack/webpack.dev.js b/extensions/cornerstone/.webpack/webpack.dev.js index 180994fd663..1ae30844802 100644 --- a/extensions/cornerstone/.webpack/webpack.dev.js +++ b/extensions/cornerstone/.webpack/webpack.dev.js @@ -1,16 +1,8 @@ const path = require('path'); -const merge = require('webpack-merge'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); - -// +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-development - mode: 'development', - }); + return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); }; diff --git a/extensions/cornerstone/.webpack/webpack.prod.js b/extensions/cornerstone/.webpack/webpack.prod.js index cacedd1bcc8..4d0abe0a74c 100644 --- a/extensions/cornerstone/.webpack/webpack.prod.js +++ b/extensions/cornerstone/.webpack/webpack.prod.js @@ -1,6 +1,6 @@ const merge = require('webpack-merge'); const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const pkg = require('./../package.json'); const ROOT_DIR = path.join(__dirname, './..'); @@ -11,8 +11,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', devtool: 'source-map', stats: { colors: true, diff --git a/extensions/dicom-html/.webpack/webpack.dev.js b/extensions/dicom-html/.webpack/webpack.dev.js index 180994fd663..1ae30844802 100644 --- a/extensions/dicom-html/.webpack/webpack.dev.js +++ b/extensions/dicom-html/.webpack/webpack.dev.js @@ -1,16 +1,8 @@ const path = require('path'); -const merge = require('webpack-merge'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); - -// +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-development - mode: 'development', - }); + return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); }; diff --git a/extensions/dicom-html/.webpack/webpack.prod.js b/extensions/dicom-html/.webpack/webpack.prod.js index 6ec4c874423..b788a001db3 100644 --- a/extensions/dicom-html/.webpack/webpack.prod.js +++ b/extensions/dicom-html/.webpack/webpack.prod.js @@ -1,6 +1,6 @@ const merge = require('webpack-merge'); const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const pkg = require('./../package.json'); const ROOT_DIR = path.join(__dirname, './..'); @@ -11,8 +11,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', devtool: 'source-map', stats: { colors: true, diff --git a/extensions/dicom-microscopy/.webpack/webpack.dev.js b/extensions/dicom-microscopy/.webpack/webpack.dev.js index 180994fd663..1ae30844802 100644 --- a/extensions/dicom-microscopy/.webpack/webpack.dev.js +++ b/extensions/dicom-microscopy/.webpack/webpack.dev.js @@ -1,16 +1,8 @@ const path = require('path'); -const merge = require('webpack-merge'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); - -// +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-development - mode: 'development', - }); + return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); }; diff --git a/extensions/dicom-microscopy/.webpack/webpack.prod.js b/extensions/dicom-microscopy/.webpack/webpack.prod.js index aeaf013157f..2a106c37a6b 100644 --- a/extensions/dicom-microscopy/.webpack/webpack.prod.js +++ b/extensions/dicom-microscopy/.webpack/webpack.prod.js @@ -1,6 +1,6 @@ const merge = require('webpack-merge'); const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const pkg = require('./../package.json'); const ROOT_DIR = path.join(__dirname, './..'); @@ -11,8 +11,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', devtool: 'source-map', stats: { colors: true, diff --git a/extensions/dicom-pdf/.webpack/webpack.dev.js b/extensions/dicom-pdf/.webpack/webpack.dev.js index 180994fd663..1ae30844802 100644 --- a/extensions/dicom-pdf/.webpack/webpack.dev.js +++ b/extensions/dicom-pdf/.webpack/webpack.dev.js @@ -1,16 +1,8 @@ const path = require('path'); -const merge = require('webpack-merge'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); - -// +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-development - mode: 'development', - }); + return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); }; diff --git a/extensions/dicom-pdf/.webpack/webpack.prod.js b/extensions/dicom-pdf/.webpack/webpack.prod.js index 02b27112c53..15b9a59d594 100644 --- a/extensions/dicom-pdf/.webpack/webpack.prod.js +++ b/extensions/dicom-pdf/.webpack/webpack.prod.js @@ -1,6 +1,6 @@ const merge = require('webpack-merge'); const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const pkg = require('./../package.json'); const ROOT_DIR = path.join(__dirname, './..'); @@ -11,8 +11,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', devtool: 'source-map', stats: { colors: true, diff --git a/extensions/vtk/.webpack/webpack.dev.js b/extensions/vtk/.webpack/webpack.dev.js index 180994fd663..1ae30844802 100644 --- a/extensions/vtk/.webpack/webpack.dev.js +++ b/extensions/vtk/.webpack/webpack.dev.js @@ -1,16 +1,8 @@ const path = require('path'); -const merge = require('webpack-merge'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); - -// +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-development - mode: 'development', - }); + return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); }; diff --git a/extensions/vtk/.webpack/webpack.prod.js b/extensions/vtk/.webpack/webpack.prod.js index 6ad317ec154..307a8eea679 100644 --- a/extensions/vtk/.webpack/webpack.prod.js +++ b/extensions/vtk/.webpack/webpack.prod.js @@ -1,6 +1,6 @@ const merge = require('webpack-merge'); const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const pkg = require('./../package.json'); const ROOT_DIR = path.join(__dirname, './..'); @@ -11,8 +11,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', devtool: 'source-map', stats: { colors: true, diff --git a/extensions/vtk/package.json b/extensions/vtk/package.json index 6b1208ed45f..a75de7229cb 100644 --- a/extensions/vtk/package.json +++ b/extensions/vtk/package.json @@ -48,8 +48,7 @@ }, "dependencies": { "@babel/runtime": "^7.5.5", - "react-vtkjs-viewport": "0.0.11", - "vtk.js": "^9.5.0" + "react-vtkjs-viewport": "0.0.11" }, "devDependencies": { "@ohif/core": "^0.50.3", diff --git a/extensions/vtk/src/utils/setLayoutAndViewportData.js b/extensions/vtk/src/utils/setLayoutAndViewportData.js index c8223cd3b20..671e1ec1dbf 100644 --- a/extensions/vtk/src/utils/setLayoutAndViewportData.js +++ b/extensions/vtk/src/utils/setLayoutAndViewportData.js @@ -1,4 +1,4 @@ -import { redux } from "@ohif/core"; +import { redux } from '@ohif/core'; const { setViewportLayoutAndData } = redux.actions; diff --git a/maintainer-notes.md b/maintainer-notes.md index cf7c7e8a81f..6b13303ade6 100644 --- a/maintainer-notes.md +++ b/maintainer-notes.md @@ -17,13 +17,7 @@ yarn add --dev -W package-name project - Remove all-contributors bot; install CLI per project and add per project commands -- Verify all have "dev:package-name" command - - Should we include `package.json` and `src` as output? (build from ESM) - - Should we remove `dev:package-name` commands and suggest navigating to - package root? - Fix broken peer dependencies? -- Lingering core-js resolution issues when building for Viewer PWA (from project - directory) ## ORBS @@ -35,20 +29,6 @@ yarn add --dev -W package-name Debug Note: `http://localhost:3000/webpack-dev-server` -NOTES: - -# bumps pre-release version of all packages if any changes - -- `npx lerna version prerelease` - -# Releases based on package.json differences from NPM - -- `npx lerna publish from-package --dist-tag canary` - -Use Env options to set config: - -- https://webpack.js.org/api/cli/#environment-options - ## Bundling - Extensions must bundle all assets into a single file for UMD diff --git a/package.json b/package.json index ce398b55b68..34458c777de 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,12 @@ "dev:project": ".scripts/dev.sh", "build": "lerna run build:viewer --stream", "build:ci": "lerna run build:viewer:ci --stream", + "build:demo": "lerna run build:viewer:demo --stream", "build:package": "lerna run build:viewer:package --stream", "build:package-all": "lerna run build:package --parallel --stream", - "test": "yarn run test:unit && yarn run test:e2e:ci", + "test": "yarn run test:unit", "test:unit": "jest --collectCoverage", "test:unit:ci": "lerna run test:unit:ci --parallel --stream", - "test:e2e:ci": "cd platform/viewer && yarn run test:e2e:ci", "see-changed": "lerna changed", "docs:publish": "chmod +x ./build-and-publish-docs.sh && ./build-and-publish-docs.sh", "release": "yarn run lerna:version && yarn run lerna:publish", @@ -35,8 +35,10 @@ "devDependencies": { "@babel/core": "^7.5.0", "@babel/plugin-proposal-class-properties": "^7.5.0", - "@babel/plugin-proposal-object-rest-spread": "^7.5.0", + "@babel/plugin-proposal-object-rest-spread": "^7.5.5", "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", "@babel/plugin-transform-runtime": "^7.5.0", "@babel/preset-env": "^7.5.0", "@babel/preset-react": "^7.0.0", @@ -91,11 +93,5 @@ }, "resolutions": { "**/@babel/runtime": "7.5.5" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ] + } } diff --git a/platform/core/.webpack/webpack.dev.js b/platform/core/.webpack/webpack.dev.js new file mode 100644 index 00000000000..1ae30844802 --- /dev/null +++ b/platform/core/.webpack/webpack.dev.js @@ -0,0 +1,8 @@ +const path = require('path'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); +const SRC_DIR = path.join(__dirname, '../src'); +const DIST_DIR = path.join(__dirname, '../dist'); + +module.exports = (env, argv) => { + return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); +}; diff --git a/platform/core/.webpack/webpack.prod.js b/platform/core/.webpack/webpack.prod.js index fd561e55dd8..a5c1eec77b4 100644 --- a/platform/core/.webpack/webpack.prod.js +++ b/platform/core/.webpack/webpack.prod.js @@ -1,6 +1,6 @@ const merge = require('webpack-merge'); const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const pkg = require('./../package.json'); const ROOT_DIR = path.join(__dirname, './..'); @@ -11,8 +11,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', devtool: 'source-map', stats: { colors: true, diff --git a/platform/core/src/measurements/classes/MeasurementApi.js b/platform/core/src/measurements/classes/MeasurementApi.js index d5612659d67..60f3dea7fc0 100644 --- a/platform/core/src/measurements/classes/MeasurementApi.js +++ b/platform/core/src/measurements/classes/MeasurementApi.js @@ -5,9 +5,10 @@ import getDescription from '../lib/getDescription'; import getImageIdForImagePath from '../lib/getImageIdForImagePath'; import guid from '../../utils/guid'; import studyMetadataManager from '../../utils/studyMetadataManager'; +import { measurementApiDefaultConfig } from './../configuration.js'; const configuration = { - measurementTools: [], + ...measurementApiDefaultConfig, }; export default class MeasurementApi { diff --git a/platform/core/src/measurements/classes/TimepointApi.js b/platform/core/src/measurements/classes/TimepointApi.js index 12d893100c2..92af8805143 100644 --- a/platform/core/src/measurements/classes/TimepointApi.js +++ b/platform/core/src/measurements/classes/TimepointApi.js @@ -1,6 +1,9 @@ import log from '../../log'; +import { timepointApiDefaultConfig } from './../configuration.js'; -const configuration = {}; +const configuration = { + ...timepointApiDefaultConfig, +}; const TIMEPOINT_TYPE_NAMES = { prebaseline: 'Pre-Baseline', diff --git a/platform/core/src/measurements/configuration.js b/platform/core/src/measurements/configuration.js index e82925868e2..c8e15247713 100644 --- a/platform/core/src/measurements/configuration.js +++ b/platform/core/src/measurements/configuration.js @@ -1,4 +1,3 @@ -import { TimepointApi, MeasurementApi } from './classes'; import { allTools } from './toolGroups/allTools'; import { retrieveMeasurements, @@ -10,7 +9,7 @@ import { disassociateStudy, } from './dataExchange'; -MeasurementApi.setConfiguration({ +const measurementApiDefaultConfig = { measurementTools: [allTools], newLesions: [ { @@ -28,9 +27,9 @@ MeasurementApi.setConfiguration({ retrieve: retrieveMeasurements, store: storeMeasurements, }, -}); +}; -TimepointApi.setConfiguration({ +const timepointApiDefaultConfig = { dataExchange: { retrieve: retrieveTimepoints, store: storeTimepoints, @@ -38,4 +37,6 @@ TimepointApi.setConfiguration({ update: updateTimepoint, disassociate: disassociateStudy, }, -}); +}; + +export { measurementApiDefaultConfig, timepointApiDefaultConfig }; diff --git a/platform/core/src/measurements/index.js b/platform/core/src/measurements/index.js index 0b84a138517..20b55b6fe50 100644 --- a/platform/core/src/measurements/index.js +++ b/platform/core/src/measurements/index.js @@ -1,9 +1,6 @@ -import './configuration'; - import * as tools from './tools'; import { MeasurementApi, TimepointApi } from './classes'; - import { ConformanceCriteria } from './conformance'; import MeasurementHandlers from './measurementHandlers'; import getDescription from './lib/getDescription'; diff --git a/platform/i18n/.webpack/webpack.dev.js b/platform/i18n/.webpack/webpack.dev.js index 180994fd663..1ae30844802 100644 --- a/platform/i18n/.webpack/webpack.dev.js +++ b/platform/i18n/.webpack/webpack.dev.js @@ -1,16 +1,8 @@ const path = require('path'); -const merge = require('webpack-merge'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); - -// +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-development - mode: 'development', - }); + return webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); }; diff --git a/platform/i18n/.webpack/webpack.prod.js b/platform/i18n/.webpack/webpack.prod.js index ed1926af1a4..9865b26c8ff 100644 --- a/platform/i18n/.webpack/webpack.prod.js +++ b/platform/i18n/.webpack/webpack.prod.js @@ -1,6 +1,6 @@ const merge = require('webpack-merge'); const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const pkg = require('./../package.json'); const ROOT_DIR = path.join(__dirname, './..'); @@ -11,8 +11,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', devtool: 'source-map', stats: { colors: true, diff --git a/platform/ui/.webpack/webpack.prod.js b/platform/ui/.webpack/webpack.prod.js index 6b7e20bdb53..da7b819bb9b 100644 --- a/platform/ui/.webpack/webpack.prod.js +++ b/platform/ui/.webpack/webpack.prod.js @@ -1,6 +1,6 @@ const merge = require('webpack-merge'); const path = require('path'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); const pkg = require('./../package.json'); const ROOT_DIR = path.join(__dirname, './..'); @@ -11,8 +11,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', devtool: 'source-map', stats: { colors: true, diff --git a/platform/viewer/.browserslistrc b/platform/viewer/.browserslistrc new file mode 100644 index 00000000000..c9285e5d6be --- /dev/null +++ b/platform/viewer/.browserslistrc @@ -0,0 +1,7 @@ +# Browsers that we support + +> 1% +IE 11 +not IE < 11 +not dead +not op_mini all diff --git a/platform/viewer/.webpack/all.dev.js b/platform/viewer/.webpack/all.dev.js deleted file mode 100644 index 28f698d8ccd..00000000000 --- a/platform/viewer/.webpack/all.dev.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Notice that we're not extracting CSS or generating a service-worker. This - * may create a slightly inconsistent experience, but should allow for faster/ - * easier development. - * - * We do still need to generate the "index.html" and copy over files from - * "public/" so our `webpack-dev-server` can _serve_ them for us :+1: - */ -const path = require('path'); -const merge = require('webpack-merge'); -const webpack = require('webpack'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); -// Plugins -const CopyWebpackPlugin = require('copy-webpack-plugin'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -// Const -const SRC_DIR = path.join(__dirname, '../src'); -const DIST_DIR = path.join(__dirname, '../dist'); -const PUBLIC_DIR = path.join(__dirname, '../public'); -const ASSET_PATH = process.env.ASSET_PATH || '/'; -// Env Vars -const HTML_TEMPLATE = process.env.HTML_TEMPLATE || 'index.html'; -const PUBLIC_URL = process.env.PUBLIC_URL || '/'; -const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js'; - -module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); - - return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-development - mode: 'development', - output: { - path: DIST_DIR, // push to common? - publicPath: ASSET_PATH, - // filename: '[name].bundle.js', - }, - plugins: [ - new webpack.HotModuleReplacementPlugin(), - // Copy "Public" Folder to Dist - new CopyWebpackPlugin([ - { - from: PUBLIC_DIR, - to: DIST_DIR, - toType: 'dir', - // Ignore our HtmlWebpackPlugin template file - // Ignore our configuration files - ignore: ['config/*', 'html-templates/*', '.DS_Store'], - }, - // Copy over and rename our target app config file - { - from: `${PUBLIC_DIR}/${APP_CONFIG}`, - to: `${DIST_DIR}/app-config.js`, - }, - ]), - // Generate "index.html" w/ correct includes/imports - new HtmlWebpackPlugin({ - template: `${PUBLIC_DIR}/html-templates/${HTML_TEMPLATE}`, - filename: 'index.html', - templateParameters: { - PUBLIC_URL: PUBLIC_URL, - }, - }), - ], - // https://webpack.js.org/configuration/dev-server/ - devServer: { - hot: true, - open: true, - port: 3000, - historyApiFallback: { - disableDotRule: true, - }, - }, - }); -}; diff --git a/platform/viewer/.webpack/rules/extractStyleChunks.js b/platform/viewer/.webpack/rules/extractStyleChunks.js new file mode 100644 index 00000000000..24dc0597a12 --- /dev/null +++ b/platform/viewer/.webpack/rules/extractStyleChunks.js @@ -0,0 +1,35 @@ +const ExtractCssChunksPlugin = require('extract-css-chunks-webpack-plugin'); + +function extractStyleChunks(isProdBuild) { + return [ + { + test: /\.styl$/, + use: [ + { + loader: ExtractCssChunksPlugin.loader, + options: { + hot: !isProdBuild, + }, + }, + { loader: 'css-loader' }, + { loader: 'stylus-loader' }, + ], + }, + { + test: /\.(sa|sc|c)ss$/, + use: [ + { + loader: ExtractCssChunksPlugin.loader, + options: { + hot: !isProdBuild, + }, + }, + 'css-loader', + 'postcss-loader', + // 'sass-loader', + ], + }, + ]; +} + +module.exports = extractStyleChunks; diff --git a/platform/viewer/.webpack/rules/fontsToJavaScript.js b/platform/viewer/.webpack/rules/fontsToJavaScript.js new file mode 100644 index 00000000000..b95e5b202f1 --- /dev/null +++ b/platform/viewer/.webpack/rules/fontsToJavaScript.js @@ -0,0 +1,20 @@ +/** + * For CommonJS, we want to bundle whatever font we've landed on. This allows + * us to reduce the number of script-tags we need to specify for simple use. + * + * PWA will grab these externally to reduce bundle size (think code split), + * and cache the grab using service-worker. + */ +const fontsToJavaScript = { + test: /\.(ttf|eot|woff|woff2)$/i, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + }, + }, + ], +}; + +module.exports = fontsToJavaScript; diff --git a/platform/viewer/.webpack/commonjs.prod.js b/platform/viewer/.webpack/webpack.commonjs.js similarity index 59% rename from platform/viewer/.webpack/commonjs.prod.js rename to platform/viewer/.webpack/webpack.commonjs.js index d94b23a608d..3c0b005fdfc 100644 --- a/platform/viewer/.webpack/commonjs.prod.js +++ b/platform/viewer/.webpack/webpack.commonjs.js @@ -1,9 +1,9 @@ const path = require('path'); const merge = require('webpack-merge'); -const webpack = require('webpack'); -const webpackCommon = require('./../../../.webpack/webpack.common.js'); +const webpackCommon = require('./../../../.webpack/webpack.commonjs.js'); // const { CleanWebpackPlugin } = require('clean-webpack-plugin'); +const fontsToJavaScriptRule = require('./rules/fontsToJavaScript.js'); // const const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); @@ -12,8 +12,6 @@ module.exports = (env, argv) => { const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', entry: { bundle: `${SRC_DIR}/index-umd.js`, }, @@ -39,27 +37,8 @@ module.exports = (env, argv) => { libraryTarget: 'umd', filename: 'index.umd.js', }, - /** - * For CommonJS, we want to bundle whatever font we've landed on. This allows - * us to reduce the number of script-tags we need to specify for simple use. - * - * PWA will grab these externally to reduce bundle size (think code split), - * and cache the grab using service-worker. - */ module: { - rules: [ - { - test: /\.(ttf|eot|woff|woff2)$/i, - use: [ - { - loader: 'file-loader', - options: { - name: '[name].[ext]', - }, - }, - ], - }, - ], + rules: [fontsToJavaScriptRule], }, plugins: [ // Clean output.path diff --git a/platform/viewer/.webpack/pwa.prod.js b/platform/viewer/.webpack/webpack.pwa.js similarity index 52% rename from platform/viewer/.webpack/pwa.prod.js rename to platform/viewer/.webpack/webpack.pwa.js index 5eeffb10f95..ba4c1f94c5c 100644 --- a/platform/viewer/.webpack/pwa.prod.js +++ b/platform/viewer/.webpack/webpack.pwa.js @@ -1,34 +1,40 @@ +// ~~ WebPack const path = require('path'); const merge = require('webpack-merge'); const webpack = require('webpack'); -const webpackCommon = require('./../../../.webpack/webpack.common-pwa.js'); -// Plugins +const webpackBase = require('./../../../.webpack/webpack.base.js'); +// ~~ Plugins +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') + .BundleAnalyzerPlugin; const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const ExtractCssChunksPlugin = require('extract-css-chunks-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const WorkboxPlugin = require('workbox-webpack-plugin'); const TerserJSPlugin = require('terser-webpack-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const workboxPlugin = require('workbox-webpack-plugin'); -const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') - .BundleAnalyzerPlugin; -// +// ~~ Rules +const extractStyleChunksRule = require('./rules/extractStyleChunks.js'); +// ~~ Directories const SRC_DIR = path.join(__dirname, '../src'); const DIST_DIR = path.join(__dirname, '../dist'); const PUBLIC_DIR = path.join(__dirname, '../public'); -// Env Vars +// ~~ Env Vars const HTML_TEMPLATE = process.env.HTML_TEMPLATE || 'index.html'; const PUBLIC_URL = process.env.PUBLIC_URL || '/'; const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js'; module.exports = (env, argv) => { - const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR }); + const baseConfig = webpackBase(env, argv, { SRC_DIR, DIST_DIR }); + const isProdBuild = process.env.NODE_ENV === 'production'; - return merge(commonConfig, { - // https://webpack.js.org/configuration/mode/#mode-production - mode: 'production', - // Out of memory -- Code Split - // devtool: 'source-map', + const mergedConfig = merge(baseConfig, { + devtool: isProdBuild ? 'source-map' : 'cheap-module-eval-source-map', + output: { + path: DIST_DIR, + filename: isProdBuild ? '[name].bundle.[chunkhash].js' : '[name].js', + publicPath: PUBLIC_URL, // Used by HtmlWebPackPlugin for asset prefix + }, stats: { colors: true, hash: true, @@ -41,86 +47,31 @@ module.exports = (env, argv) => { warnings: true, }, optimization: { - minimize: true, + minimize: isProdBuild, sideEffects: true, - minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})], - }, - output: { - path: DIST_DIR, - filename: '[name].bundle.[chunkhash].js', - publicPath: PUBLIC_URL, // Used by HtmlWebPackPlugin for asset prefix + // // TODO: For more granular minimize + // // minimizer: [ + // // new TerserJSPlugin({ + // // sourceMap: true, + // // terserOptions: { + // // sourceMap: { + // // file: '[name].map', + // // url: 'https://my-host/[url]', + // // }, + // // }, + // // }), + // // new OptimizeCSSAssetsPlugin({}), + // // ], }, module: { - rules: [ - { - test: /\.styl$/, - use: [ - { - loader: ExtractCssChunksPlugin.loader, - options: { - hot: process.env.NODE_ENV === 'development', - }, - }, - { loader: 'css-loader' }, - { loader: 'stylus-loader' }, - ], - }, - { - test: /\.(sa|sc|c)ss$/, - use: [ - { - loader: ExtractCssChunksPlugin.loader, - options: { - hot: process.env.NODE_ENV === 'development', - }, - }, - 'css-loader', - 'postcss-loader', - // 'sass-loader', - ], - }, - ], + rules: [...extractStyleChunksRule(isProdBuild)], }, - module: { - rules: [ - { - test: /\.styl$/, - use: [ - { - loader: ExtractCssChunksPlugin.loader, - options: { - hot: process.env.NODE_ENV === 'development', - }, - }, - { loader: 'css-loader' }, - { loader: 'stylus-loader' }, - ], - }, - { - test: /\.(sa|sc|c)ss$/, - use: [ - { - loader: ExtractCssChunksPlugin.loader, - options: { - hot: process.env.NODE_ENV === 'development', - }, - }, - 'css-loader', - 'postcss-loader', - // 'sass-loader', - ], - }, - ], - }, - // TODO: - // Do we need to rip anything out of the more generic common.js we're - // merging with this? plugins: [ // Uncomment to generate bundle analyzer // new BundleAnalyzerPlugin(), // Clean output.path new CleanWebpackPlugin(), - // "Public" Folder + // Copy "Public" Folder to Dist new CopyWebpackPlugin([ { from: PUBLIC_DIR, @@ -142,10 +93,7 @@ module.exports = (env, argv) => { chunkFilename: '[id].css', ignoreOrder: false, // Enable to remove warnings about conflicting order }), - /** - * This generates our index.html file from the specified template. - * This is the easiest way to inject custom configuration and extensions. - */ + // Generate "index.html" w/ correct includes/imports new HtmlWebpackPlugin({ template: `${PUBLIC_DIR}/html-templates/${HTML_TEMPLATE}`, filename: 'index.html', @@ -154,11 +102,31 @@ module.exports = (env, argv) => { }, // favicon: `${PUBLIC_DIR}/favicon.ico`, }), - new workboxPlugin.GenerateSW({ + new WorkboxPlugin.GenerateSW({ swDest: 'sw.js', clientsClaim: true, skipWaiting: true, }), ], + // https://webpack.js.org/configuration/dev-server/ + devServer: { + // gzip compression of everything served + // Causes Cypress: `wait-on` issue in CI + // compress: true, + // http2: true, + // https: true, + hot: true, + open: true, + port: 3000, + historyApiFallback: { + disableDotRule: true, + }, + }, }); + + if (!isProdBuild) { + mergedConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); + } + + return mergedConfig; }; diff --git a/platform/viewer/README.md b/platform/viewer/README.md index 0256baaba65..bfe9eeb8fea 100644 --- a/platform/viewer/README.md +++ b/platform/viewer/README.md @@ -12,7 +12,6 @@
Demo | - Roadmap | Component Library
@@ -95,7 +94,9 @@ guide. ### E2E Tests -Using [Cypress](https://www.cypress.io/) to create End-to-End tests and check whether the application flow is performing correctly, ensuring that the integrated components are working as expected. +Using [Cypress](https://www.cypress.io/) to create End-to-End tests and check +whether the application flow is performing correctly, ensuring that the +integrated components are working as expected. #### Why Cypress? @@ -146,10 +147,10 @@ When creating tests, place the test file "next to" the file you're testing. ```js // File -index.js +index.js; // Test for file -index.test.js +index.test.js; ``` As you add and modify code, `jest` will watch for uncommitted changes and run @@ -157,32 +158,6 @@ your tests, reporting the results to your terminal. Make a pull request with your changes to `master`, and a core team member will review your work. If you have any questions, please don't hesitate to reach out via a GitHub issue. -## Roadmap - -If you want to know what's planned for the very near future, -[check out our roadmap](https://ohif.canny.io/). The best way to influence when -and what is worked on is to contribute to the conversation by creating GitHub -issues, and contributing code through pull requests. OHIF's high level -priorities for the near future are: - -- Feature parity with version 1 -- Extension and configuration improvements with key integration partners -- Continued Developer Experience Improvements -- Segmentation Tools, and improved VTK.js support - -More granular information will make it's way to the backlog as these items -become scoped for development by core maintainers. - -> Don't hesitate to ask questions, propose features, or create pull requests. -> We're here, we're listening, and we're ready to build the best open source -> medical imaging viewer on the web. - -#### Roadmap Generously Powered by Canny.io - - - - - ## Contributors Thanks goes to these wonderful people diff --git a/platform/viewer/package.json b/platform/viewer/package.json index 25ac868e29a..361cf6723fc 100644 --- a/platform/viewer/package.json +++ b/platform/viewer/package.json @@ -17,13 +17,13 @@ }, "proxy": "http://localhost:8042", "scripts": { - "build:package": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/commonjs.prod.js", - "build:viewer": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/pwa.prod.js", - "build:viewer:ci": "cross-env NODE_ENV=production PUBLIC_URL=/pwa/ APP_CONFIG=config/netlify.js node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/pwa.prod.js", - "build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/pwa.prod.js", + "build:package": "cross-env NODE_ENV=production node --max_old_space_size=8192 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.commonjs.js", + "build:viewer": "cross-env NODE_ENV=production node --max_old_space_size=8192 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js", + "build:viewer:ci": "cross-env NODE_ENV=production PUBLIC_URL=/pwa/ APP_CONFIG=config/netlify.js node --max_old_space_size=8192 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js", + "build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html node --max_old_space_size=8192 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js", "build:viewer:package": "yarn run build:package", - "dev": "webpack-dev-server --config .webpack/all.dev.js -w", - "dev:orthanc": "cross-env APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start", + "dev": "cross-env NODE_ENV=development webpack-dev-server --config .webpack/webpack.pwa.js -w", + "dev:orthanc": "cross-env NODE_ENV=developmen APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start", "dev:viewer": "yarn run dev", "start": "yarn run dev", "orthanc:up": "docker-compose -f docker/Nginx-Orthanc/docker-compose.yml up", @@ -31,10 +31,6 @@ "test:unit": "jest --watchAll", "test:unit:ci": "jest --ci --runInBand --collectCoverage" }, - "resolutions": { - "browserslist": "4.6.2", - "caniuse-lite": "1.0.30000974" - }, "files": [ "dist", "README.md" @@ -55,10 +51,10 @@ "@ohif/ui": "^0.50.1", "@tanem/react-nprogress": "^1.1.25", "classnames": "^2.2.6", - "core-js": "^3.1.4", + "core-js": "^3.2.1", "cornerstone-core": "^2.2.8", "cornerstone-math": "^0.1.8", - "cornerstone-tools": "^3.15.1", + "cornerstone-tools": "^3.19.2", "cornerstone-wado-image-loader": "^3.0.0", "dcmjs": "^0.4.7", "dicom-parser": "^1.8.3", @@ -81,7 +77,8 @@ "redux-logger": "^3.0.6", "redux-oidc": "3.1.x", "redux-thunk": "^2.3.0", - "reselect": "^4.0.0" + "reselect": "^4.0.0", + "vtk.js": "^11.0.1" }, "devDependencies": { "cypress": "^3.3.1", diff --git a/platform/viewer/public/config/demo.js b/platform/viewer/public/config/demo.js index fd0c0a3df7f..eca2a470c36 100644 --- a/platform/viewer/public/config/demo.js +++ b/platform/viewer/public/config/demo.js @@ -1,5 +1,6 @@ window.config = { routerBasename: '/', + extensions: [], showStudyList: true, servers: { dicomWeb: [ @@ -17,9 +18,51 @@ window.config = { }, ], }, + hotkeys: [ + { + commandName: 'incrementActiveViewport', + label: 'Next Image Viewport', + keys: ['right'], + }, + { + commandName: 'decrementActiveViewport', + label: 'Previous Image Viewport', + keys: ['left'], + }, + { commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] }, + { commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] }, + { commandName: 'invertViewport', label: 'Invert', keys: ['i'] }, + { + commandName: 'flipViewportVertical', + label: 'Flip Horizontally', + keys: ['h'], + }, + { + commandName: 'flipViewportHorizontal', + label: 'Flip Vertically', + keys: ['v'], + }, + { commandName: 'scaleUpViewport', label: 'Zoom In', keys: ['+'] }, + { commandName: 'scaleDownViewport', label: 'Zoom Out', keys: ['-'] }, + { commandName: 'fitViewportToWindow', label: 'Zoom to Fit', keys: ['='] }, + { commandName: 'resetViewport', label: 'Reset', keys: ['space'] }, + { commandName: 'nextImage', label: 'Next Image', keys: ['down'] }, + { commandName: 'previousImage', label: 'Previous Image', keys: ['up'] }, + { + commandName: 'nextViewportDisplaySet', + label: 'Previous Series', + keys: ['pagedown'], + }, + { + commandName: 'previousViewportDisplaySet', + label: 'Next Series', + keys: ['pageup'], + }, + { commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] }, + ], i18n: { LOCIZE_PROJECTID: 'a8da3f9a-e467-4dd6-af33-474d582a0294', LOCIZE_API_KEY: null, // Developers can use this to do in-context editing. DO NOT COMMIT THIS KEY! - USE_LOCIZE: true - } -} + USE_LOCIZE: true, + }, +}; diff --git a/platform/viewer/public/html-templates/index.html b/platform/viewer/public/html-templates/index.html index 6957b5c5be2..fa2a326252b 100644 --- a/platform/viewer/public/html-templates/index.html +++ b/platform/viewer/public/html-templates/index.html @@ -9,6 +9,9 @@ + + + OHIF Viewer diff --git a/platform/viewer/server.js b/platform/viewer/server.js new file mode 100644 index 00000000000..96d08ece2ba --- /dev/null +++ b/platform/viewer/server.js @@ -0,0 +1,1024 @@ +/** + * @author Szymon Dziaล‚owski + * @date 29 Nov 2017 + * @license MIT + * @homepage https://github.com/stopsopa/npx-server + */ +var http = require('http'); + +var path = require('path'); + +var fs = require('fs'); + +const spawn = require('child_process').spawn; + +var thisScript = path.basename(__filename); + +var script = 'node ' + thisScript; + +var sp = ['node', [thisScript]]; + +var staticServer = false; +// var staticServer = false; + +let staticServerAbs = false; + +if (staticServer) { + + staticServerAbs = path.resolve(__dirname, staticServer); +} + +process.on('SIGINT', function (signal) { + console.log(`signal SIGINT..., signal: ${signal}`) + process.exit(0); +}); +process.on('SIGTERM', function (signal) { + console.log(`signal SIGTERM..., signal: ${signal}`) + process.exit(0); +}); + +const log = function () { + Array.prototype.slice.call(arguments).map(i => i + "\n").forEach(i => process.stdout.write(i)); +}; + +function isArray(obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; +}; +function isObject(a) { + return Object.prototype.toString.call(a) === '[object Object]'; +}; + + +var mkdirP = (function () { + const module = {}; + /** + * https://github.com/substack/node-mkdirp/blob/master/index.js + */ + +var path = require('path'); +var fs = require('fs'); +var _0777 = parseInt('0777', 8); + +module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; + +function mkdirP (p, opts, f, made) { + if (typeof opts === 'function') { + f = opts; + opts = {}; + } + else if (!opts || typeof opts !== 'object') { + opts = { mode: opts }; + } + + var mode = opts.mode; + var xfs = opts.fs || fs; + + if (mode === undefined) { + mode = _0777 & (~process.umask()); + } + if (!made) made = null; + + var cb = f || function () {}; + p = path.resolve(p); + + xfs.mkdir(p, mode, function (er) { + if (!er) { + made = made || p; + return cb(null, made); + } + switch (er.code) { + case 'ENOENT': + mkdirP(path.dirname(p), opts, function (er, made) { + if (er) cb(er, made); + else mkdirP(p, opts, cb, made); + }); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + xfs.stat(p, function (er2, stat) { + // if the stat fails, then that's super weird. + // let the original error be the failure reason. + if (er2 || !stat.isDirectory()) cb(er, made) + else cb(null, made); + }); + break; + } + }); +} + +mkdirP.sync = function sync (p, opts, made) { + if (!opts || typeof opts !== 'object') { + opts = { mode: opts }; + } + + var mode = opts.mode; + var xfs = opts.fs || fs; + + if (mode === undefined) { + mode = _0777 & (~process.umask()); + } + if (!made) made = null; + + p = path.resolve(p); + + try { + xfs.mkdirSync(p, mode); + made = made || p; + } + catch (err0) { + switch (err0.code) { + case 'ENOENT' : + made = sync(path.dirname(p), opts, made); + sync(p, opts, made); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + var stat; + try { + stat = xfs.statSync(p); + } + catch (err1) { + throw err0; + } + if (!stat.isDirectory()) throw err0; + break; + } + } + + return made; +}; + return module.exports; +}()) + + +const prepareDir = target => { + + try { + + mkdirP.sync(target); + } + catch (e) { + + process.stdout.write(`\n ERROR prepareDir: ${e}\n`); + + process.exit(1); + } +}; + +const raceThrottleDebounce = (function () { + + var crypto = require('crypto'); + + return function (fn) { + + var last = false; + + var triggeredFor = false; + + var args; + + var newFn = function () { + + last = (new Date()).getTime() + crypto.randomBytes(5).toString('hex'); + + args = Array.prototype.slice.call(arguments); + + if (triggeredFor) { + + return ; + } + + triggeredFor = last; + + return fn.apply(this, args); + }; + + newFn.unlock = function () { + + if (triggeredFor === last) { + + return triggeredFor = last = false; + } + + triggeredFor = false; + + newFn.apply(this, args); + }; + + return newFn; + } +}()); + +const args = (function (obj, tmp) { + process.argv + .slice(2) + .map(a => { + + if (a.indexOf('--') === 0) { + + tmp = a.substring(2).replace(/^\s*(\S*(\s+\S+)*)\s*$/, '$1'); + + if (tmp) { + + obj[tmp] = (typeof obj[tmp] === 'undefined') ? true : obj[tmp]; + } + + return; + } + + if (a === 'true') { + + a = true + } + + if (a === 'false') { + + a = false + } + + if (tmp !== null) { + + if (obj[tmp] === true) { + + return obj[tmp] = [a]; + } + + try { + + obj[tmp].push(a); + } + catch (e) { + + } + } + }) + ; + + Object.keys(obj).map(k => { + (obj[k] !== true && obj[k].length === 1) && (obj[k] = obj[k][0]); + (obj[k] === 'false') && (obj[k] = false); + }); + + return { + all: () => JSON.parse(JSON.stringify(obj)), + get: (key, def) => { + + var t = JSON.parse(JSON.stringify(obj)); + + if (typeof def === 'undefined') + + return t[key]; + + return (typeof t[key] === 'undefined') ? def : t[key] ; + }, + update: data => { + + delete data['config']; + + delete data['dump']; + + delete data['help']; + + delete data['inject']; + + obj = data; + } + }; +}({})); + +// const config = {/* */} +// const log = console.log; + +// // // https://nodejs.org/docs/latest/api/all.html#modules_accessing_the_main_module +// if (require.main === module) { + +// function isObject(a) { +// return ['[object Object]',"[object Array]"].indexOf(Object.prototype.toString.call(a)) > -1; +// }; + +// const a = process.argv.slice(2); + +// if (a.indexOf('--param') > -1) { + +// const key = ( a[1] || '' ).split('.'); + +// let k, tmp = config; + +// while (k = key.shift()) { + +// tmp = tmp[k]; +// } + +// if (isObject(tmp)) { + +// process.stdout.write(JSON.stringify(tmp, null, ' ')); +// } +// else { + +// process.stdout.write(tmp + ''); +// } + +// } + +// } +// else { + +// module.exports = config; +// } + +if (args.get('help')) { + + let ssman = ''; + + if (staticServer) { + + ssman = ` + --gc "/path" + + generate controller /path in directory '${staticServerAbs}' +`; + } + + process.stdout.write(` +Standalone static files http server with no dependencies + +@homepage https://github.com/stopsopa/npx-server +@date 29 Nov 2017 +@license MIT +@author Szymon Dziaล‚owski https://github.com/stopsopa + +parameters: + + --port [port] def: 8080 + + --dir [path] def: '.' + relative or absolute path to directory with files to serve + + --config [filepath.json] def: false + + path to config file (json format), file can containe object where + kays are parameters of this script ('config' param in file will be ignored) + + --noindex def: false + disable indexing directories content if url points to directory + + --log [level] def: 1 + + binary mask: + + 0 - show nothing + 1 - show 404, + 2 - show 200, + 4 - show 301 + 8 - autoindex + + more examples: + 3 - show 404 and 200 + 6 - show 200 and 301 + 7 - show all without autoindex + 15 - show all + + --watch [regex] def: false + + reload currently opened page in browser when files will change + + examples: + node ${thisScript} --watch - watch all files (can be slow) + node ${thisScript} --watch '/\\.js$/i' - reload only when files with 'js' extension will change + node ${thisScript} --watch '\\.js$' - like above but shorter syntax (if no regex flags) + node ${thisScript} --watch '/\\.js$/i' --watch '/\\.html$/i' - reload for 'js' and 'html' files + node ${thisScript} --watch '/\\.(js|html)$/i' - like above but in one regex + + --ignore [regex] def: '/^(.*?\\/)?\\.[^\\/]+$/g' (all files starting from ".") + + ignore watching files (this param takes precedense over --watch param) + + + --debug [true|false] def: false + + flag for debugging --watch and --ignore parameters behaviour + + --dump + + output config + ${ssman} + --flag + + just extra allowed flag for searching processes using 'ps aux | grep [flagvalue]' + +`); + process.exit(0); +} + +var gc = args.get('gc'); + +if (staticServer && gc) { + + let file = gc.replace(/[^a-z\d-_]/g, '') + '.js'; + + if ( ! file ) { + + process.stdout.write(`Can't generate path from url '${gc}'`); + + process.exit(1); + } + + let checkPath = gc; + + if (gc.indexOf('/') === 0) { + + checkPath = checkPath.substring(1); + } + + checkPath = path.resolve(__dirname, checkPath); + + if (fs.existsSync(checkPath)) { + + process.stdout.write(`Error:\n Can't create controller '${checkPath}' path is already taken`); + + process.exit(1); + } + + file = path.resolve(staticServerAbs, file); + + prepareDir(path.dirname(file)); + + if (fs.existsSync(file)) { + + process.stdout.write(`Error:\n Controller '${file}' already exist`); + + process.exit(1); + } + + fs.appendFileSync(file, ` + +// https://nodejs.org/api/http.html#http_class_http_serverresponse + +const controller = (req, res, query = {}, json = {}) => { + + res.setHeader('Content-Type', 'application/json; charset=utf-8'); + // res.setHeader('Content-Type', 'text/plain; charset=utf-8'); + + // res.statusCode = 404; + + res.end(JSON.stringify({ + page: { + query, + json, + }, + node: process.version, + })); +} + +controller.url = '${gc}'; + +module.exports = controller; +`); + + if ( fs.existsSync(file) ) { + + process.stdout.write(`Controller '${file}' successfully created`); + } + else { + + process.stdout.write(`Error:\n Controller '${file}' couldn't be created`); + + process.exit(1); + } + + process.exit(0); +} + +var config = args.get('config'); + +var dump = args.get('dump'); + +if (config) { + + var configData = require(path.resolve(__dirname, config)); + + if ( ! isObject(configData) ) { + + throw `data from config file '${config}' should be an object`; + } + + args.update(Object.assign(configData, args.all())); +} + +args.update(args.all()); + +if (dump) { + + log(JSON.stringify(args.all(), null, ' ')); +} + +const diff = function(a, b) { + return a.filter(function(i) {return b.indexOf(i) < 0}); +}; + +(function (d) { + if (d.length) { + + log(`Unknown parameters: ${d.join(', ')}\ncheck \n\n node ${thisScript} --help\n\nfor more help`); + + process.exit(1); + } +}(diff(Object.keys(args.all()), ('port dir noindex log help watch ignore inject debug config dump flag' + (staticServer ? ' gc' : '')).split(' ')))); + +function execArgs (args, str) { + var arr = ['--inject']; + Object.keys(args).forEach(key => { + if (['watch', 'ignore'].indexOf(key) > -1) { + + return; + } + if (isArray(args[key])) { + args[key].forEach(val => { + arr.push('--' + key) + arr.push(val) + }); + } + else { + if (args[key] === true) { + arr.push('--' + key) + } + else { + arr.push('--' + key) + arr.push(args[key]) + } + } + }); + + if (str) { + + return arr.map(a => '"' + (a + '').replace(/"/g, '\\"') + '"').join(' ') + } + + return arr; +} + +var dir = path.resolve(__dirname, args.get('dir', '.')); + +var regexps = (function () { + function split(reg) { + + var tmp = reg.substring(1).match(/^(.*)\/([^\/]*)$/); + + if (tmp) { + + return tmp.slice(1); + } + + return [reg]; + } + return function (list, debug) { + return list.filter(i => (typeof i === 'string')).filter(i => i.replace(/^\s*(\S*(\s+\S+)*)\s*$/, '$1')).map(i => { + if (i[0] === '/') { + i = split(i); + return new RegExp(i[0], i[1]); + } + return new RegExp(i); + }); + + } +}()); + +var debug = args.get('debug'); + +var ignore = args.get('ignore', '/^\\./'); + +if (ignore === true) { + + ignore = false; +} +else { + + if ( ! isArray(ignore)) { + ignore = [ignore]; + } + + ignore = regexps(ignore).filter(i => i); + + if (ignore.length === 0) { + + ignore = false; + } +} + +var watch = args.get('watch', false); + +if (typeof watch !== 'boolean') { + + if ( ! isArray(watch) ) { + + watch = [watch]; + } + + watch = regexps(watch); + + if (watch.length === 0) { + + watch = true; + } +} + +script += ' ' + execArgs(args.all(), true); + +sp[1] = sp[1].concat(execArgs(args.all())); + +if (watch) { + + var child; + + var event = raceThrottleDebounce(function (eventType, filename) { + + debug && log('try: ' + filename); + + if (filename) { + + if (isArray(ignore)) { + + for (var i = 0, l = ignore.length ; i < l ; i += 1 ) { + + debug && log(`before test (ignore): /${ignore[i].source}/${ignore[i].flags} against: `+ filename); + + if (ignore[i].test(filename)) { + + debug && log(`ignored: /${ignore[i].source}/${ignore[i].flags} `+ filename); + + return event.unlock(); + } + } + } + + if (isArray(watch)) { + + for (var matched = false, i = 0, l = watch.length ; i < l ; i += 1 ) { + + debug && log(`before test (watch): /${watch[i].source}/${watch[i].flags} against: `+ filename); + + if (watch[i].test(filename)) { + + debug && log(`matched: /${watch[i].source}/${watch[i].flags} `+ filename); + + matched = true; + + break; + } + } + + if ( ! matched ) { + + return event.unlock(); + } + } + } + + if (child) { + + log(eventType + ': ' + filename + ', restarting process: ' + script); + + child.kill(); + } + + child = spawn(sp[0], sp[1]); + + child.stdout.on('data', (data) => process.stdout.write(data)); + + event.unlock(); + }); + + event(); + + fs.watch(dir, { + recursive: true + }, event); +} +else { + + var port = parseInt(args.get('port', 8080), 10); + + var logs = parseInt(args.get('log', 1), 10); + + var inject = args.get('inject'); + + var type = (function (types) { + return function (req, res, ext) { + + ext = ext || path.extname(req.url.toLowerCase().split('?')[0]).replace(/[^a-z0-9]/g, ''); + + types[ext] && res.setHeader('Content-Type', types[ext]); + + return ext; + } + }((function (type) { + type.jpeg = type.jpg; + type.log = type.txt; + return type; + }({ + html : 'text/html; charset=utf-8', + js : 'application/javascript; charset=utf-8', + css : 'text/css; charset=utf-8', + json : 'application/json; charset=utf-8', + txt : 'text/plain; charset=utf-8', + gif : 'image/gif', + bmp : 'image/bmp', + jpg : 'image/jpeg', + png : 'image/png', + pdf : 'application/pdf', + ico : 'image/x-icon', + })))); + + function time() { + return (new Date()).toISOString().substring(0, 19).replace('T', ' '); + } + + var server = http.createServer().listen(port); + + function noAccess(req, res, isDir, notype) { + + res.statusCode = 403; + + type(req, res, 'html'); + + (logs & 2) && log(`${time()} \x1b[35m${res.statusCode}\x1b[0m: ${req.url}`); + + res.end(`
${notype ? '' : (isDir ? 'directory' : 'file')} ${req.url} no access.
`); + } + + var uniq = (function unique(pattern) { + return pattern.replace(/[xy]/g, + function(c) { + var r = Math.random() * 16 | 0, + v = c == 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); + }('xyxyxyxyxyxyx')); + + function addWatcher(content, ext) { + + if (inject && ext === 'html') { + + content = content.replace( + /(<\s*\/\s*body\s*>)/i, + `$1` + ); + } + + return content; + } + + const controllers = () => { + + const dir = path.resolve(__dirname, staticServer); + + if ( ! fs.existsSync(dir) ) { + + return []; + } + + return fs.readdirSync(dir) + .reduce((acc, file) => { + + const lib = path.resolve(dir, file); + + try { + + const ext = path.extname(file); + + if (ext !== '.js') { + + return acc; + }; + + delete require.cache[lib]; + + const module = require(lib); + + module.__file = lib; + + acc.push(module); + } + catch (e) { + + log(`controllers error [${lib}]: `, e) + } + + return acc; + }, []) + ; + } + + // base64 online encoder: https://xaviesteve.com//pro/base64.php + const favicon = new Buffer('iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAFdQTFRF/////v7+7e3t4+Pj4uLi7u7urKysSEhINjY2SUlJtLS0GhoaMzMzysrK5OTkODg4S0tLHR0duLi4MjIySkpK5eXl7+/vHBwc8/PzbGxsNTU18fHx7u/vzVzHUQAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFiUAABYlAUlSJPAAAADdSURBVDjLnZPZEoMgDEWBQAVF0Nq9/f/vbBAXNnXa++KMOQPJMRIShi4h8XsGLlxQj5AUOFVyjKpJMaxqtKvrRrEiAFK3BsC0WsIG4Avz8x/g4AqhsElrsclO5FU3ca2k7nstu3Oh7JxQhsfjNYKWgKjRySks6GJ1AjKnCSAypwGAPZh2SAZePxxYnAJnsbGyX4DDK3yTl7nJySlNPaDTMbPTDKDCXDHmFojaBbITCiajpRHb27kxZgjcS6LWPJ4vuQuQN7ijh4Pt/KQms6Qms/WljHPuf+O8XvjtMV9rxg4RtlXOXgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOC0xMS0yN1QxMDowMzowMSswMDowMIg1+6IAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTgtMTEtMjdUMTA6MDM6MDErMDA6MDD5aEMeAAAARnRFWHRzb2Z0d2FyZQBJbWFnZU1hZ2ljayA2LjcuOC05IDIwMTQtMDUtMTIgUTE2IGh0dHA6Ly93d3cuaW1hZ2VtYWdpY2sub3Jn3IbtAAAAABh0RVh0VGh1bWI6OkRvY3VtZW50OjpQYWdlcwAxp/+7LwAAABh0RVh0VGh1bWI6OkltYWdlOjpoZWlnaHQAMTkyDwByhQAAABd0RVh0VGh1bWI6OkltYWdlOjpXaWR0aAAxOTLTrCEIAAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1lADE1NDMzMTI5ODEv0kVFAAAAD3RFWHRUaHVtYjo6U2l6ZQAwQkKUoj7sAAAAVnRFWHRUaHVtYjo6VVJJAGZpbGU6Ly8vbW50bG9nL2Zhdmljb25zLzIwMTgtMTEtMjcvNzMzODU0Y2FjM2I1MGI4NGE3NmIwODY1MmY4NDdjYjQuaWNvLnBuZwnzw3IAAAAASUVORK5CYII=', 'base64'); + + server.on('request', function (req, res) { + + var url = req.url.split('?')[0]; + + if (req.url === '/favicon.ico') { + + (logs & 4) && log(`${time()} \x1b[33m${res.statusCode}\x1b[0m: ${url}`); + + res.statusCode = 200; + res.setHeader('Content-Type', 'image/x-icon'); + res.setHeader("Cache-Control", "public, max-age=2592000"); // expiers after a month + res.setHeader("Expires", new Date(Date.now() + 2592000000).toUTCString()); + return res.end(favicon); + } + + if (req.url === '/run-sandbox-server.sh-check') { + + res.statusCode = 201; + + return res.end('ok') + } + + if (inject) { + + var test = req.url.match(/\?watch=(.*)/); + + if (test) { + + if (test[1] !== uniq) { + + return res.end(uniq) + } + + return; + } + } + + // (function (a) { + // if (url.indexOf(a) === 0) { + // url = url.substring(a.length); + // } + // }('/app_dev.php')); + + var query = req.url.split('?')[1]; + + if (typeof query === 'string') { + + query = query.split('&').reduce((acc, val) => { + var + a = val.split(/=/), + key = a.shift(), + dec = a.join('=') + ; + acc[key] = decodeURIComponent(dec); + return acc; + }, {}); + + if (typeof query._redirect === 'string') { + + res.writeHead(query._status || 301, { 'Location': query._redirect }); + + return setTimeout(() => res.end(), query._timeout ? (parseInt(query._timeout, 10) || 0) : 0); + } + } + + var file = path.resolve(dir, '.' + path.sep + (decodeURI(url).replace(/\.\.+/g, '.'))); + + if (fs.existsSync(file)) { + + var isDir = fs.statSync(file).isDirectory(); + + if (isDir) { + + if (args.get('noindex')) { + + return noAccess(req, res, isDir, true); + } + + if (url.length > 1 && url.substr(-1) !== '/') { + + res.writeHead(302, { 'Location': url + '/' }); + + (logs & 4) && log(`${time()} \x1b[33m${res.statusCode}\x1b[0m: ${url} -> ${url + '/'}`); + + return res.end(); + } + + try { + + var list = ` + + + + + + + + + + '; + } + catch (e) { + + return noAccess(req, res, isDir); + } + + (logs & 8) && log(`${time()} \x1b[36m${res.statusCode}\x1b[0m: [\x1b[36mautoindex\x1b[0m] ${req.url}`); + + return res.end(addWatcher(list, type(req, res, 'html'))); + } + + try { + + res.end(addWatcher(fs.readFileSync(file), type(req, res))); + } + catch (e) { + + return noAccess(req, res, isDir); + } + + (logs & 2) && log(`${time()} \x1b[32m${res.statusCode}\x1b[0m: ${req.url}`); + } + else { + + let found = false; + + if (staticServer) { + + found = controllers().find(c => c.url === url); + } + + if (found) { + + + let json=''; + req.setEncoding('utf8'); + req.on('data', function(chunk) { + json += chunk; + }); + + req.on('end', function() { + + try { + + json = JSON.parse(json); + + } catch (e) { + + json = e; + } + + try { + + found(req, res, query, json); + } + catch (e) { + + res.setHeader(`Content-Type`, `application/json; charset=utf-8`); + + res.statusCode = 500; + + res.end(JSON.stringify({ + exception: 'General controller exception', + controller: found.__file, + exceptionMessage: e.message, + exceptionMessageSplit: (e.message + '').split("\n") + })); + } + + }); + + (logs & 1) && log(`${time()} \x1b[93m${res.statusCode}\x1b[0m: ${req.url}`); + } + else { + + res.statusCode = 404; + + res.end(`
status code ${res.statusCode}: ${req.url}
`); + + (logs & 1) && log(`${time()} \x1b[31m${res.statusCode}\x1b[0m: ${req.url}`); + } + } + }); + + log(` + ๐ŸŒŽ Listening on port ${port}, start time: ${time()} + serving files from directory ${dir}, --help for more info + `); + +} diff --git a/platform/viewer/src/App.js b/platform/viewer/src/App.js index 4b8ae641411..b39dc6421d0 100644 --- a/platform/viewer/src/App.js +++ b/platform/viewer/src/App.js @@ -2,12 +2,6 @@ import { hot } from 'react-hot-loader/root'; import './config'; -// Polyfills -// PWA Only? -import 'core-js/features/array/flat'; -import 'core-js/stable'; -import 'regenerator-runtime/runtime'; - import { CommandsManager, ExtensionManager, diff --git a/platform/viewer/src/index.js b/platform/viewer/src/index.js index 810ac087624..01132f88737 100644 --- a/platform/viewer/src/index.js +++ b/platform/viewer/src/index.js @@ -2,6 +2,9 @@ * Entry point for development and production PWA builds. * Packaged (NPM) builds go through `index-umd.js` */ + +import 'regenerator-runtime/runtime'; + import App from './App.js'; import React from 'react'; import ReactDOM from 'react-dom'; diff --git a/platform/viewer/src/store/index.js b/platform/viewer/src/store/index.js index f97b867de48..3a9a11cb5cc 100644 --- a/platform/viewer/src/store/index.js +++ b/platform/viewer/src/store/index.js @@ -2,6 +2,7 @@ import { applyMiddleware, combineReducers, createStore, + compose, } from 'redux/es/redux.js'; // import { createLogger } from 'redux-logger'; @@ -13,7 +14,8 @@ import thunkMiddleware from 'redux-thunk'; // Combine our ohif-core, ui, and oidc reducers // Set init data, using values found in localStorage const { reducers, localStorage } = redux; -// const loggerMiddleware = createLogger(); +const middleware = [thunkMiddleware]; +const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; reducers.ui = layoutReducers; reducers.oidc = oidcReducer; @@ -22,10 +24,7 @@ const rootReducer = combineReducers(reducers); const store = createStore( rootReducer, localStorage.loadState(), // preloadedState - applyMiddleware( - thunkMiddleware // Lets us dispatch() functions - // loggerMiddleware // neat middleware that logs actions - ) + composeEnhancers(applyMiddleware(...middleware)) ); // When the store's preferences change, diff --git a/postcss.config.js b/postcss.config.js index 65869342e71..bf6e73388c4 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,9 +1,13 @@ -module.exports = { - // parser: "sugarss", - parser: false, - plugins: { - "postcss-import": {}, - "postcss-preset-env": {}, - cssnano: {} - } +module.exports = function(ctx) { + ctx = ctx || {}; + ctx.env = ctx.env || 'development'; + + return { + map: ctx.env === 'development' ? ctx.map : false, + plugins: { + 'postcss-import': {}, + 'postcss-preset-env': {}, + cssnano: ctx.env === 'production' ? {} : false, + }, + }; }; diff --git a/yarn.lock b/yarn.lock index 6c725a63963..32534e1077a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -400,7 +400,7 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@7.5.5", "@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.4.3", "@babel/plugin-proposal-object-rest-spread@^7.5.0", "@babel/plugin-proposal-object-rest-spread@^7.5.5": +"@babel/plugin-proposal-object-rest-spread@7.5.5", "@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.4.3", "@babel/plugin-proposal-object-rest-spread@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz#61939744f71ba76a3ae46b5eea18a54c16d22e58" integrity sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw== @@ -1105,7 +1105,21 @@ pirates "^4.0.0" source-map-support "^0.5.9" -"@babel/runtime@7.1.2", "@babel/runtime@7.4.3", "@babel/runtime@7.5.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5": +"@babel/runtime@7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.2.tgz#81c89935f4647706fc54541145e6b4ecfef4b8e3" + integrity sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg== + dependencies: + regenerator-runtime "^0.12.0" + +"@babel/runtime@7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.3.tgz#79888e452034223ad9609187a0ad1fe0d2ad4bdc" + integrity sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA== + dependencies: + regenerator-runtime "^0.13.2" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132" integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ== @@ -4092,13 +4106,13 @@ browserslist@^4.0.0, browserslist@^4.1.0, browserslist@^4.5.2, browserslist@^4.6 node-releases "^1.1.23" browserslist@^4.6.3, browserslist@^4.6.4, browserslist@^4.6.6: - version "4.6.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.6.tgz#6e4bf467cde520bc9dbdf3747dafa03531cec453" - integrity sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA== + version "4.7.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.0.tgz#9ee89225ffc07db03409f2fee524dc8227458a17" + integrity sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA== dependencies: - caniuse-lite "^1.0.30000984" - electron-to-chromium "^1.3.191" - node-releases "^1.1.25" + caniuse-lite "^1.0.30000989" + electron-to-chromium "^1.3.247" + node-releases "^1.1.29" bser@^2.0.0: version "2.1.0" @@ -4399,7 +4413,7 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000974: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000974.tgz#b7afe14ee004e97ce6dc73e3f878290a12928ad8" integrity sha512-xc3rkNS/Zc3CmpMKuczWEdY2sZgx09BkAxfvkxlAEBTqcMHeL8QnPqhKse+5sRTi3nrw2pJwToD2WvKn1Uhvww== -caniuse-lite@^1.0.30000955, caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000984: +caniuse-lite@^1.0.30000955, caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989: version "1.0.30000989" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz#b9193e293ccf7e4426c5245134b8f2a56c0ac4b9" integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw== @@ -5310,7 +5324,7 @@ core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0, core-js@^2.5.7, core-js@^2.6.5: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== -core-js@^3.0.0, core-js@^3.1.4: +core-js@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.2.0.tgz#0a835fdf6aa677fff83a823a7b5276c9e7cebb76" integrity sha512-gybgLzmr7SQRSF6UzGYXducx4eE10ONQlyEnQoqiGPbmbn7zLkb73tPfc4YbZN0lvcTQwoLNPjq4RuCaCumGyQ== @@ -5345,7 +5359,7 @@ cornerstone-math@^0.1.8: resolved "https://registry.yarnpkg.com/cornerstone-math/-/cornerstone-math-0.1.8.tgz#68ab1f9e4fdcd7c5cb23a0d2eb4263f9f894f1c5" integrity sha512-x7NEQHBtVG7j1yeyj/aRoKTpXv1Vh2/H9zNLMyqYJDtJkNng8C4Q8M3CgZ1qer0Yr7eVq2x+Ynmj6kfOm5jXKw== -cornerstone-tools@^3.13.0, cornerstone-tools@^3.15.1: +cornerstone-tools@^3.13.0: version "3.18.3" resolved "https://registry.yarnpkg.com/cornerstone-tools/-/cornerstone-tools-3.18.3.tgz#a4f892867f816b7a774edea046522af793d3e10d" integrity sha512-/jLNexVupGRLgxrtp7IE1en9n0x/Qj9HI5GLDDKTf4kBZl5eKToIkir83W1aqi+K1Hk1DR1Pb2lgxWT1NYvcsA== @@ -5354,6 +5368,14 @@ cornerstone-tools@^3.13.0, cornerstone-tools@^3.15.1: cornerstone-math "0.1.7" debug "4.1.1" +cornerstone-tools@^3.19.2: + version "3.19.2" + resolved "https://registry.yarnpkg.com/cornerstone-tools/-/cornerstone-tools-3.19.2.tgz#0cf3b2f3fe6fa1ec2585a5b90b0ba0cf0a20c913" + integrity sha512-oigCrT/cmgg5qWvRR65sTFONMG7tm4XcSNX5bTmiqOQ5enoDgCXdICbdxb/8PBFvsMHzJrBw0tC4qkJLkTiupw== + dependencies: + "@babel/runtime" "7.1.2" + cornerstone-math "0.1.7" + cornerstone-wado-image-loader@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cornerstone-wado-image-loader/-/cornerstone-wado-image-loader-3.0.0.tgz#250ba435379096815de52ed80629d6407e016841" @@ -6705,10 +6727,10 @@ ejs@^2.6.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.2.tgz#3a32c63d1cd16d11266cd4703b14fec4e74ab4f6" integrity sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q== -electron-to-chromium@^1.3.122, electron-to-chromium@^1.3.191: - version "1.3.225" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.225.tgz#c6786475b5eb5f491ade01a78b82ba2c5bfdf72b" - integrity sha512-7W/L3jw7HYE+tUPbcVOGBmnSrlUmyZ/Uyg24QS7Vx0a9KodtNrN0r0Q/LyGHrcYMtw2rv7E49F/vTXwlV/fuaA== +electron-to-chromium@^1.3.122, electron-to-chromium@^1.3.247: + version "1.3.250" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.250.tgz#1f383c16aeb75e7bddbd6a0491237eca81b2cb1f" + integrity sha512-2OAU91iUw83QvzuWJPfT+FMj+O+DC1EyTx1QBFcc9WZzOQSfZEAWINpdLWElxkgfiqTvQRDOKg0DkMZd9QoNug== electron-to-chromium@^1.3.150: version "1.3.224" @@ -12311,7 +12333,14 @@ node-pre-gyp@^0.12.0: semver "^5.3.0" tar "^4" -node-releases@^1.1.13, node-releases@^1.1.23, node-releases@^1.1.25: +node-releases@^1.1.13, node-releases@^1.1.29: + version "1.1.29" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.29.tgz#86a57c6587a30ecd6726449e5d293466b0a0bb86" + integrity sha512-R5bDhzh6I+tpi/9i2hrrvGJ3yKPYzlVOORDkXhnZuwi5D3q1I5w4vYy24PJXTcLk9Q0kws9TO77T75bcK8/ysQ== + dependencies: + semver "^5.3.0" + +node-releases@^1.1.23: version "1.1.27" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.27.tgz#b19ec8add2afe9a826a99dceccc516104c1edaf4" integrity sha512-9iXUqHKSGo6ph/tdXVbHFbhRVQln4ZDTIBJCzsa90HimnBYc5jw8RWYt4wBYFHehGyC3koIz5O4mb2fHrbPOuA== @@ -15266,6 +15295,11 @@ regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regenerator-runtime@^0.13.2: version "0.13.3" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" @@ -18296,10 +18330,10 @@ void-elements@^2.0.1: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= -vtk.js@^9.5.0: - version "9.7.0" - resolved "https://registry.yarnpkg.com/vtk.js/-/vtk.js-9.7.0.tgz#763767607a958fba5c70754434612f3066bd96a0" - integrity sha512-4IJJr2slOY+W/GjUdjElg3ViJSt6IF+siIJ4FmqOYQeOdTKRVxVYb7dAYVOH3MyVz8Zs39DEwJHHhRK5hkjsjg== +vtk.js@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/vtk.js/-/vtk.js-11.0.1.tgz#a22a499eaac96a31a30e48f30a9dd7ac51f5587b" + integrity sha512-v5f6ItYQrdwE0FomKEy//oNYrFpD6CWaKjxbI6N5+ttsKLVtKwGmpYtB8bii0Tww1c50g0uo9tcj6tvKTUv62Q== dependencies: blueimp-md5 "2.10.0" commander "2.11.0"