Improve production build (#1542)

* production build using esbuild

* build browser tests with esbuild

* use tsc-alias

* remove webpack

* changelog

* update eslint to v9

* pr feedback

* update build

* include src map by default
This commit is contained in:
David Sehnal
2025-06-17 18:15:10 +02:00
committed by GitHub
parent 6c2d5b9da7
commit f8a5237024
22 changed files with 13514 additions and 24008 deletions

View File

@@ -1,4 +0,0 @@
node_modules/*
build/*
docs/site/*
lib/*

View File

@@ -1,122 +0,0 @@
{
"env": {
"browser": true,
"node": true
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"impliedStrict": true
}
},
"rules": {
"indent": "off",
"arrow-parens": [
"off",
"as-needed"
],
"brace-style": "off",
"comma-spacing": "off",
"space-infix-ops": "off",
"comma-dangle": "off",
"eqeqeq": [
"error",
"smart"
],
"import/order": "off",
"no-eval": "warn",
"no-new-wrappers": "warn",
"no-trailing-spaces": "error",
"no-unsafe-finally": "warn",
"no-var": "error",
"spaced-comment": "error",
"semi": "warn",
"no-restricted-syntax": [
"error",
{
"selector": "ExportDefaultDeclaration",
"message": "Default exports are not allowed"
}
],
"no-throw-literal": "error",
"key-spacing": "error",
"object-curly-spacing": ["error", "always"],
"array-bracket-spacing": "error",
"space-in-parens": "error",
"computed-property-spacing": "error",
"prefer-const": ["error", {
"destructuring": "all",
"ignoreReadBeforeAssign": false
}],
"space-before-function-paren": "off",
"func-call-spacing": "off",
"no-multi-spaces": "error",
"block-spacing": "error",
"keyword-spacing": "off",
"space-before-blocks": "error",
"semi-spacing": "error",
"no-constant-binary-expression": "error"
},
"overrides": [
{
"files": ["**/*.ts", "**/*.tsx"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["tsconfig.json", "tsconfig.commonjs.json"],
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/class-name-casing": "off",
"@typescript-eslint/indent": [
"error",
4
],
"@typescript-eslint/member-delimiter-style": [
"off",
{
"multiline": {
"delimiter": "none",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/prefer-namespace-keyword": "warn",
"@typescript-eslint/quotes": [
"error",
"single",
{
"avoidEscape": true,
"allowTemplateLiterals": true
}
],
"@typescript-eslint/semi": [
"off",
null
],
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/brace-style": [
"error",
"1tbs", { "allowSingleLine": true }
],
"@typescript-eslint/comma-spacing": "error",
"@typescript-eslint/space-infix-ops": "error",
"@typescript-eslint/space-before-function-paren": ["error", {
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}],
"@typescript-eslint/func-call-spacing": ["error"],
"@typescript-eslint/keyword-spacing": ["error"]
}
}
]
}

View File

@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file, following t
Note that since we don't clearly distinguish between a public and private interfaces there will be changes in non-major versions that are potentially breaking. If we make breaking changes to less used interfaces we will highlight it in here.
## [Unreleased]
- Update production build to use `esbuils`
- Emit explicit paths in `import`s in `lib/`
## [v4.18.0] - 2025-06-08
- MolViewSpec extension:

109
eslint.config.mjs Normal file
View File

@@ -0,0 +1,109 @@
import { defineConfig } from "eslint/config";
import globals from "globals";
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
export default defineConfig([{
ignores: [
"node_modules/*",
"build/*",
"docs/site/*",
"lib/*",
"eslint.config.mjs",
"build.mjs",
]
},{
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
ecmaVersion: 2018,
sourceType: "module",
parserOptions: {
ecmaFeatures: {
impliedStrict: true,
},
},
},
rules: {
indent: "off",
"arrow-parens": ["off", "as-needed"],
"brace-style": ["error", "1tbs", {
allowSingleLine: true,
}],
"comma-spacing": "off",
"space-infix-ops": "off",
"comma-dangle": "off",
eqeqeq: ["error", "smart"],
"import/order": "off",
"no-eval": "warn",
"no-extend-native": "warn",
"no-new-wrappers": "warn",
"no-trailing-spaces": "error",
"no-unsafe-finally": "warn",
"no-self-compare": "warn",
"no-var": "error",
"spaced-comment": "error",
semi: "warn",
"no-restricted-syntax": ["error", {
selector: "ExportDefaultDeclaration",
message: "Default exports are not allowed",
}],
"no-throw-literal": "error",
"key-spacing": "error",
"object-curly-spacing": ["error", "always"],
"array-bracket-spacing": "error",
"space-in-parens": "error",
"computed-property-spacing": "error",
"prefer-const": ["error", {
destructuring: "all",
ignoreReadBeforeAssign: false,
}],
"space-before-function-paren": "off",
"func-call-spacing": "off",
"no-multi-spaces": "error",
"block-spacing": "error",
"keyword-spacing": "warn",
"space-before-blocks": "error",
"semi-spacing": "error",
"no-constant-binary-expression": "error",
},
}, {
files: ["**/*.ts", "**/*.tsx"],
plugins: {
"@typescript-eslint": typescriptEslint,
},
languageOptions: {
parser: tsParser,
ecmaVersion: 5,
sourceType: "module",
parserOptions: {
project: ["tsconfig.eslint.json"],
},
},
rules: {
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/class-name-casing": "off",
"@typescript-eslint/member-delimiter-style": ["off", {
multiline: {
delimiter: "none",
requireLast: true,
},
singleline: {
delimiter: "semi",
requireLast: false,
},
}],
"@typescript-eslint/prefer-namespace-keyword": "warn",
"@typescript-eslint/semi": ["off", null],
},
}]);

36853
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -18,28 +18,18 @@
"lint-fix": "eslint . --fix",
"test": "npm install --no-save \"gl@^6.0.2\" && npm run lint && jest",
"jest": "jest",
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
"clean": "node ./scripts/clean.js",
"build": "npm run build:apps && npm run build:lib",
"build:apps": "node ./scripts/build.mjs -a -e --prd",
"build:lib": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\" && npm run build:lib-extra",
"build:lib-extra": "node scripts/write-version.mjs && cpx \"src/**/*.{scss,html,ico,jpg}\" lib/ && cpx \"src/**/*.{scss,html,ico,jpg}\" lib/commonjs/ && tsc-alias -p tsconfig.json",
"rebuild": "npm run clean && npm run build",
"build-viewer": "npm run build-tsc && npm run build-extra && npm run build-webpack-viewer",
"build-tsc": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\"",
"build-extra": "cpx \"src/**/*.{scss,html,ico,jpg}\" lib/",
"build-webpack": "webpack --mode production --config ./webpack.config.production.js",
"build-webpack-viewer": "webpack --mode production --config ./webpack.config.viewer.js",
"watch": "concurrently -c \"green,green,gray,gray\" --names \"tsc,srv,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-servers\" \"npm:watch-extra\" \"npm:watch-webpack\"",
"watch-viewer": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"",
"watch-viewer-debug": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer-debug\"",
"watch-tsc": "tsc --watch --incremental",
"watch-servers": "tsc --build tsconfig.commonjs.json --watch --incremental",
"watch-extra": "cpx \"src/**/*.{scss,html,ico,jpg}\" lib/ --watch",
"watch-webpack": "webpack -w --mode development --stats minimal",
"watch-webpack-viewer": "webpack -w --mode development --stats minimal --config ./webpack.config.viewer.js",
"watch-webpack-viewer-debug": "webpack -w --mode development --stats minimal --config ./webpack.config.viewer.debug.js",
"dev": "node build-dev.mjs",
"dev:all": "node build-dev.mjs -a -e",
"dev:viewer": "node build-dev.mjs -a viewer",
"dev:apps": "node build-dev.mjs -a",
"dev:examples": "node build-dev.mjs -e",
"dev": "node ./scripts/build.mjs",
"dev:all": "node ./scripts/build.mjs -a -e -bt",
"dev:viewer": "node ./scripts/build.mjs -a viewer",
"dev:apps": "node ./scripts/build.mjs -a",
"dev:examples": "node ./scripts/build.mjs -e",
"dev:browser-tests": "node ./scripts/build.mjs -bt",
"serve": "http-server -p 1338 -g",
"model-server": "node lib/commonjs/servers/model/server.js",
"model-server-watch": "nodemon --watch lib lib/commonjs/servers/model/server.js",
@@ -127,7 +117,8 @@
"Ventura Rivera <venturaxrivera@gmail.com>",
"Andy Turner <agdturner@gmail.com>",
"Lukáš Polák <admin@lukaspolak.cz>",
"Chetan Mishra <chetan.s115@gmail.com>"
"Chetan Mishra <chetan.s115@gmail.com>",
"Zach Charlop-Powers <zach.charlop.powers@gmail.com>"
],
"license": "MIT",
"devDependencies": {
@@ -137,36 +128,26 @@
"@types/pngjs": "^6.0.5",
"@types/react": "^18.3.23",
"@types/react-dom": "^18.3.7",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@typescript-eslint/eslint-plugin": "^8.34.0",
"@typescript-eslint/parser": "^8.34.0",
"benchmark": "^2.1.4",
"concurrently": "^9.1.2",
"cpx2": "^8.0.0",
"crypto-browserify": "^3.12.1",
"css-loader": "^7.1.2",
"esbuild": "^0.25.5",
"esbuild-sass-plugin": "^3.3.1",
"eslint": "^8.57.1",
"extra-watch-webpack-plugin": "^1.0.3",
"file-loader": "^6.2.0",
"eslint": "^9.29.0",
"fs-extra": "^11.3.0",
"http-server": "^14.1.1",
"jest": "^29.7.0",
"jpeg-js": "^0.4.4",
"mini-css-extract-plugin": "^2.9.2",
"path-browserify": "^1.0.1",
"raw-loader": "^4.0.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"sass": "^1.89.1",
"sass-loader": "^16.0.5",
"simple-git": "^3.28.0",
"stream-browserify": "^3.0.0",
"style-loader": "^4.0.0",
"ts-jest": "^29.3.4",
"typescript": "^5.8.3",
"webpack": "^5.99.9",
"webpack-cli": "^6.0.1"
"tsc-alias": "^1.8.16",
"typescript": "^5.8.3"
},
"dependencies": {
"@types/argparse": "^2.0.17",

View File

@@ -97,31 +97,52 @@ function examplesCssRenamePlugin({ root }) {
};
}
async function watch(app) {
function resolveEntryPath(path) {
if (!fs.existsSync(path)) {
return path + 'x'; // fallback to .tsx
}
return path;
}
function getPaths(app) {
if (app.kind === 'app') {
return {
prefix: `./build/${app.name}`,
entry: resolveEntryPath(`./src/apps/${app.name}/index.ts`),
outfile: `./build/${app.name}/${app.filename || 'molstar.js'}`,
};
}
if (app.kind === 'example') {
return {
prefix: `./build/examples/${app.name}`,
entry: resolveEntryPath(`./src/examples/${app.name}/index.ts`),
outfile: `./build/examples/${app.name}/${app.filename || 'index.js'}`,
};
}
if (app.kind === 'browser-test') {
return {
prefix: `./build/tests/browser`,
entry: resolveEntryPath(`./src/tests/browser/${app.name}.ts`),
outfile: `./build/tests/browser/${app.name}.js`,
};
}
throw new Error(`Unknown app kind: ${app.kind}`);
}
async function createBundle(app) {
const { name, kind } = app;
const prefix = kind === 'app'
? `./build/${name}`
: `./build/examples/${name}`;
let entry = `./src/${kind}s/${name}/index.ts`;
if (!fs.existsSync(entry)) {
entry = `./src/${kind}s/${name}/index.tsx`;
}
let filename = app.filename;
if (!filename) {
filename = kind === 'app' ? 'molstar.js' : 'index.js';
}
const { prefix, entry, outfile } = getPaths(app);
const ctx = await esbuild.context({
entryPoints: [entry],
tsconfig: './tsconfig.json',
bundle: true,
minify: isProduction,
minifyIdentifiers: false,
sourcemap: includeSourceMap,
globalName: app.globalName || 'molstar',
outfile: kind === 'app'
? `./build/${name}/${filename}`
: `./build/examples/${name}/${filename}`,
outfile,
plugins: [
fileLoaderPlugin({ out: prefix }),
sassPlugin({
@@ -139,15 +160,40 @@ async function watch(app) {
},
color: true,
logLevel: 'info',
define: {
'process.env.DEBUG': JSON.stringify(process.env.DEBUG || false),
__MOLSTAR_PLUGIN_VERSION__: JSON.stringify(VERSION),
__MOLSTAR_BUILD_TIMESTAMP__: `${TIMESTAMP}`,
},
});
await ctx.rebuild();
await ctx.watch();
if (!isProduction) await ctx.watch();
}
function findBrowserTests(names) {
const dir = path.resolve('./src', 'tests', 'browser');
let files = fs.readdirSync(dir).filter(file => file.endsWith('.ts')).map(file => file.replace('.ts', ''));
if (names.length) {
files = files.filter(file => names.includes(file));
}
return files.map(name => ({ kind: 'browser-test', name }));
}
const argParser = new argparse.ArgumentParser({
add_help: true,
description: 'Mol* development build'
description: 'Mol* Build'
});
argParser.add_argument('--prd', {
help: 'Create a production build.',
required: false,
action: 'store_true',
});
argParser.add_argument('--no-src-map', {
help: 'Do not include source map.',
required: false,
action: 'store_true',
});
argParser.add_argument('--apps', '-a', {
help: 'Apps to build.',
@@ -159,6 +205,11 @@ argParser.add_argument('--examples', '-e', {
required: false,
nargs: '*',
});
argParser.add_argument('--browser-tests', '-bt', {
help: 'Browser Tests to build.',
required: false,
nargs: '*',
});
argParser.add_argument('--port', '-p', {
help: 'Port.',
required: false,
@@ -174,11 +225,20 @@ argParser.add_argument('--host', {
const args = argParser.parse_args();
const isProduction = !!args.prd;
const includeSourceMap = !args.no_src_map;
const VERSION = isProduction ? JSON.parse(fs.readFileSync('./package.json', 'utf8')).version : '(dev build)';
const TIMESTAMP = Date.now();
const apps = (!args.apps ? [] : (args.apps.length ? args.apps.map(a => findApp(a, 'app')).filter(a => a) : Apps.filter(a => a.kind === 'app')));
const examples = (!args.examples ? [] : (args.examples.length ? args.examples.map(e => findApp(e, 'example')).filter(a => a) : Apps.filter(a => a.kind === 'example')));
const browserTests = (!args.browser_tests ? [] : findBrowserTests(args.browser_tests));
console.log('Apps:', apps.map(a => a.name));
console.log('Examples:', examples.map(e => e.name));
console.log('Browser Tests', browserTests.map(e => e.name));
console.log('');
function getLocalIPs() {
@@ -198,13 +258,20 @@ function getLocalIPs() {
async function main() {
const promises = [];
for (const app of apps) promises.push(watch(app));
for (const example of examples) promises.push(watch(example));
console.log(isProduction ? 'Building apps...' : 'Initial build...');
console.log('Initial build...');
for (const app of apps) promises.push(createBundle(app));
for (const example of examples) promises.push(createBundle(example));
for (const browserTest of browserTests) promises.push(createBundle(browserTest));
await Promise.all(promises);
console.log('Done.');
if (isProduction) {
console.log('Done.');
process.exit(0);
}
console.log('Initial build complete.');
const ctx = await esbuild.context({});
ctx.serve({
@@ -226,4 +293,7 @@ async function main() {
console.log('Press Ctrl+C to stop.');
}
main().catch(console.error);
main().catch((err) => {
console.error(err);
process.exit(1);
});

16
scripts/write-version.mjs Normal file
View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import * as fs from 'fs';
const VERSION = JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
const TIMESTAMP = Date.now();
const file = `export var PLUGIN_VERSION = '${VERSION}';\nexport var PLUGIN_VERSION_DATE = new Date(${TIMESTAMP})`;
const files = ['./lib/mol-plugin/version.js', './lib/commonjs/mol-plugin/version.js'];
for (const f of files) {
if (!fs.existsSync(f)) continue;
fs.writeFileSync(f, file);
}

View File

@@ -62,7 +62,6 @@ export interface CubeGrid {
export type CubeGridFormat = ModelFormat<CubeGrid>;
// eslint-disable-next-line
export function CubeGridFormat(grid: CubeGrid): CubeGridFormat {
return { name: 'custom grid', kind: 'cube-grid', data: grid };
}

View File

@@ -266,7 +266,7 @@ function makeShapeGetter() {
let newMesh = false;
let newColor = false;
if (!_plyData || _plyData !== _plyData) {
if (!_plyData || _plyData !== plyData) {
newMesh = true;
}

View File

@@ -674,14 +674,12 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
if (val >= max) {
val = max;
}
/* eslint-disable eqeqeq */
if (!allowCross && handle != null && handle > 0 && val <= bounds[handle - 1]) {
val = bounds[handle - 1];
}
if (!allowCross && handle != null && handle < bounds.length - 1 && val >= bounds[handle + 1]) {
val = bounds[handle + 1];
}
/* eslint-enable eqeqeq */
const points = Object.keys(marks).map(parseFloat);
if (step !== null) {

View File

@@ -35,7 +35,7 @@ function useBehaviorReact18<T>(s: Behavior<T> | undefined) {
return (React as any).useSyncExternalStore(
React.useCallback(
(callback: () => void) => {
const sub = (s as any)?.pipe!(skip(1)).subscribe(callback)!;
const sub = (s as any)?.pipe(skip(1)).subscribe(callback);
return () => sub?.unsubscribe();
},
[s]
@@ -49,9 +49,7 @@ const _useBehavior = !!(React as any).useSyncExternalStore
: useBehaviorLegacy;
export function useBehavior<T>(s: Behavior<T>): T;
// eslint-disable-next-line
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined;
// eslint-disable-next-line
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined {
return _useBehavior(s);
}

View File

@@ -1,12 +1,15 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
declare const __MOLSTAR_BUILD_TIMESTAMP__: string | number | undefined;
declare const __MOLSTAR_PLUGIN_VERSION__: string | undefined;
/** version from package.json, to be filled in at build time */
export const PLUGIN_VERSION = '';
export const PLUGIN_VERSION = typeof __MOLSTAR_PLUGIN_VERSION__ !== 'undefined' ? __MOLSTAR_PLUGIN_VERSION__ : '(development)';
/** to be filled in at build time */
export const PLUGIN_VERSION_DATE = +new Date();
export const PLUGIN_VERSION_DATE = new Date(typeof __MOLSTAR_BUILD_TIMESTAMP__ !== 'undefined' ? +__MOLSTAR_BUILD_TIMESTAMP__ : Date.now());

View File

@@ -1,3 +1,5 @@
/* eslint-disable no-extend-native */
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
@@ -152,7 +154,7 @@ if (!String.prototype.startsWith) {
const object = {};
const $defineProperty = Object.defineProperty;
result = $defineProperty(object, object as any, object) && $defineProperty;
} catch (error) {} // eslint-disable-line no-empty
} catch (error) {}
return result;
}());
const toString = {}.toString;
@@ -193,14 +195,12 @@ if (!String.prototype.startsWith) {
'writable': true
});
} else {
// eslint-disable-next-line no-extend-native
String.prototype.startsWith = startsWith;
}
}());
}
if (!String.prototype.endsWith) {
// eslint-disable-next-line no-extend-native
String.prototype.endsWith = function (searchString, position) {
const subjectString = this.toString();
if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
@@ -213,7 +213,6 @@ if (!String.prototype.endsWith) {
}
if (!String.prototype.repeat) {
// eslint-disable-next-line no-extend-native
String.prototype.repeat = function (count) {
'use strict';
if (this === null) {
@@ -258,7 +257,6 @@ if (!String.prototype.repeat) {
}
if (!String.prototype.includes) {
// eslint-disable-next-line no-extend-native
String.prototype.includes = function (search, start) {
'use strict';
if (typeof start !== 'number') {
@@ -274,7 +272,6 @@ if (!String.prototype.includes) {
}
if (!Array.prototype.includes) {
// eslint-disable-next-line no-extend-native
Array.prototype.includes = function (searchElement /* , fromIndex */) {
'use strict';
if (this == null) {
@@ -438,13 +435,10 @@ if (Function.prototype.name === undefined && Object.defineProperty !== undefined
// Missing in IE9-11.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
// eslint-disable-next-line no-extend-native
Object.defineProperty(Function.prototype, 'name', {
get: function () {
return this.toString().match(/^\s*function\s*(\S*)\s*\(/)[1];
}
});
}

View File

@@ -1,25 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"declaration": true,
"target": "es2018",
"alwaysStrict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"sourceMap": false,
"noUnusedLocals": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"module": "CommonJS",
"esModuleInterop": true,
"moduleResolution": "node",
"isolatedModules": true,
"importHelpers": true,
"noEmitHelpers": true,
"allowSyntheticDefaultImports": true,
"jsx": "react-jsx",
"lib": [ "es2018", "dom", "ES2022.Object" ],
"rootDir": "src",
"outDir": "lib/commonjs"
},
"include": [ "src/**/*" ]
}
}

5
tsconfig.eslint.json Normal file
View File

@@ -0,0 +1,5 @@
{
"extends": "./tsconfig.json",
"include": [ "src/**/*" ],
"exclude": [ ],
}

View File

@@ -17,10 +17,14 @@
"noEmitHelpers": true,
"allowSyntheticDefaultImports": true,
"jsx": "react-jsx",
"lib": [ "es2018", "dom", "ES2022.Object" ],
"lib": [ "ES2018", "dom", "ES2022.Object" ],
"rootDir": "src",
"outDir": "lib"
},
"include": [ "src/**/*" ],
// "exclude": [ "src/servers/**/*", "src/perf-tests/*", "src/cli/**/*" ]
"exclude": [ "src/**/_spec/*" ],
"tsc-alias": {
"resolveFullPaths": true,
"verbose": true
}
}

View File

@@ -1,119 +0,0 @@
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const VERSION = require('./package.json').version;
class VersionFilePlugin {
apply() {
fs.writeFileSync(
path.resolve(__dirname, 'lib/mol-plugin/version.js'),
`export var PLUGIN_VERSION = '${VERSION}';\nexport var PLUGIN_VERSION_DATE = new Date(typeof __MOLSTAR_DEBUG_TIMESTAMP__ !== 'undefined' ? __MOLSTAR_DEBUG_TIMESTAMP__ : ${new Date().valueOf()});`);
}
}
function sharedConfig(options) {
return {
module: {
rules: [
{
test: /\.(html|ico)$/,
use: [{
loader: 'file-loader',
options: { name: '[name].[ext]' }
}]
},
{
test: /\.(s*)css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { sourceMap: false } },
{ loader: 'sass-loader', options: { sourceMap: false } },
]
},
{
test: /\.(jpg)$/i,
type: 'asset/resource',
},
]
},
plugins: [
new ExtraWatchWebpackPlugin({
files: [
'./lib/**/*.scss',
'./lib/**/*.html'
],
}),
new webpack.DefinePlugin({
'process.env.DEBUG': JSON.stringify(process.env.DEBUG),
'__MOLSTAR_DEBUG_TIMESTAMP__': webpack.DefinePlugin.runtimeValue(() => `${new Date().valueOf()}`, true)
}),
new MiniCssExtractPlugin({ filename: (options && options.cssFilename) || 'molstar.css' }),
new VersionFilePlugin(),
],
resolve: {
modules: [
'node_modules',
path.resolve(__dirname, 'lib/')
],
fallback: {
fs: false,
vm: false,
buffer: false,
crypto: require.resolve('crypto-browserify'),
path: require.resolve('path-browserify'),
stream: require.resolve('stream-browserify'),
}
},
watchOptions: {
aggregateTimeout: 750
}
};
};
function createEntry(src, outFolder, outFilename, isNode) {
return {
target: isNode ? 'node' : void 0,
entry: path.resolve(__dirname, `lib/${src}.js`),
output: { filename: `${outFilename}.js`, path: path.resolve(__dirname, `build/${outFolder}`) },
...sharedConfig()
};
}
function createEntryPoint(name, dir, out, library, options) {
const filename = options && options.filename ? options.filename : `${library || name}.js`;
return {
entry: path.resolve(__dirname, `lib/${dir}/${name}.js`),
output: { filename: filename, path: path.resolve(__dirname, `build/${out}`), library: library || out, libraryTarget: 'umd', assetModuleFilename: 'images/[hash][ext][query]', 'publicPath': '' },
...sharedConfig(options)
};
}
function createNodeEntryPoint(name, dir, out) {
return {
target: 'node',
entry: path.resolve(__dirname, `lib/${dir}/${name}.js`),
output: { filename: `${name}.js`, path: path.resolve(__dirname, `build/${out}`) },
externals: {
argparse: 'require("argparse")',
'node-fetch': 'require("node-fetch")',
'util.promisify': 'require("util.promisify")',
},
...sharedConfig()
};
}
function createApp(name, library, options) { return createEntryPoint('index', `apps/${name}`, name, library, options); }
function createExample(name) { return createEntry(`examples/${name}/index`, `examples/${name}`, 'index'); }
function createBrowserTest(name) { return createEntryPoint(name, 'tests/browser', 'tests'); }
function createNodeApp(name) { return createNodeEntryPoint('index', `apps/${name}`, name); }
module.exports = {
createApp,
createEntry,
createExample,
createBrowserTest,
createNodeEntryPoint,
createNodeApp
};

View File

@@ -1,28 +0,0 @@
const { createApp, createExample, createBrowserTest } = require('./webpack.config.common.js');
const examples = [
'proteopedia-wrapper',
'basic-wrapper',
'lighting',
'alpha-orbitals',
'alphafolddb-pae',
'mvs-stories',
'ihm-restraints',
'interactions',
'ligand-editor'
];
const tests = [
'font-atlas',
'marching-cubes',
'render-lines', 'render-mesh', 'render-shape', 'render-spheres', 'render-structure', 'render-structure-grid', 'render-text',
'parse-xtc'
];
module.exports = [
createApp('viewer', 'molstar'),
createApp('docking-viewer', 'molstar'),
createApp('mesoscale-explorer', 'molstar'),
createApp('mvs-stories', 'mvsStories', { filename: 'mvs-stories.js', cssFilename: 'mvs-stories.css' }),
...examples.map(createExample),
...tests.map(createBrowserTest)
];

View File

@@ -1,20 +0,0 @@
const { createApp, createExample } = require('./webpack.config.common.js');
const examples = [
'proteopedia-wrapper',
'basic-wrapper',
'lighting',
'alpha-orbitals',
'mvs-stories',
'ihm-restraints',
'interactions',
'ligand-editor'
];
module.exports = [
createApp('viewer', 'molstar'),
createApp('docking-viewer', 'molstar'),
createApp('mesoscale-explorer', 'molstar'),
createApp('mvs-stories', 'mvsStories', { filename: 'mvs-stories.js', cssFilename: 'mvs-stories.css' }),
...examples.map(createExample)
];

View File

@@ -1,7 +0,0 @@
const createViewer = require('./webpack.config.viewer.js')[0];
module.exports = [
{
...createViewer,
devtool: 'eval'
}
];

View File

@@ -1,6 +0,0 @@
const common = require('./webpack.config.common.js');
const createApp = common.createApp;
module.exports = [
createApp('viewer', 'molstar'),
createApp('mesoscale-explorer', 'molstar'),
];