mirror of
https://github.com/molstar/molstar.git
synced 2026-06-04 13:30:24 +08:00
simplify, add pwa files during deploy
This commit is contained in:
15
data/pwa/README.md
Normal file
15
data/pwa/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
The files in this directory are used for deploying the Mol* Viewer as a PWA (Progressive Web App) at https://molstar.org/viewer/. They may serve as an example for creating your own PWA but wont work as-is. See `/script/deploy.js` for where these files are copied and how they are transformed during deployment.
|
||||
|
||||
|
||||
## PWA features
|
||||
|
||||
- The Service Worker will cache static resources so the Viewer can be used without internet access. This works without installing, i.e., also in Firefox.
|
||||
- Once installed, file types listed in the Manifest can be opened from, e.g., the Windows File Explorer.
|
||||
|
||||
|
||||
## Notes for development
|
||||
|
||||
In Chrome you can see a list of installed PWAs at chrome://apps/. A right-click opens a menu with an option uninstall.
|
||||
|
||||
The Chrome Dev Tools have a section 'Application' to inspect and manage PWA aspects like the Manifest and Service Workers.
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"id": "/molstar/build/viewer/index.html",
|
||||
"id": "https://molstar.org/viewer/",
|
||||
"name": "Mol* Viewer",
|
||||
"short_name": "Mol*",
|
||||
"description": "Mol* Viewer",
|
||||
"description": "Mol* Viewer: a modern web app for 3D visualization and analysis of large biomolecular structures.",
|
||||
"start_url": "./index.html",
|
||||
"theme_color": "#eeffee",
|
||||
"background_color": "#eeffee",
|
||||
"theme_color": "#eeece7",
|
||||
"background_color": "#eeece7",
|
||||
"display": "standalone",
|
||||
"icons": [
|
||||
{
|
||||
44
data/pwa/pwa.js
Normal file
44
data/pwa/pwa.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Andy Turner <agdturner@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
window.addEventListener('molstarViewerCreated', e => {
|
||||
const viewer = e.detail.viewer;
|
||||
|
||||
// Handle incoming files
|
||||
if ('launchQueue' in window) {
|
||||
launchQueue.setConsumer((launchParams) => {
|
||||
if (!launchParams.files.length) return;
|
||||
|
||||
const files = [];
|
||||
for (const fileHandle of launchParams.files) {
|
||||
files.push(fileHandle.getFile());
|
||||
}
|
||||
|
||||
Promise.all(files).then((files) => {
|
||||
viewer.loadFiles(files);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Register Progressive Web App service worker.
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', function () {
|
||||
navigator.serviceWorker.register('./sw.js')
|
||||
.then(function (registration) {
|
||||
// Registration was successful
|
||||
if (molstar.isDebugMode) {
|
||||
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
||||
}
|
||||
}, function (err) {
|
||||
// registration failed :(
|
||||
if (molstar.isDebugMode) {
|
||||
console.error('ServiceWorker registration failed: ', err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
60
data/pwa/sw.js
Normal file
60
data/pwa/sw.js
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Andy Turner <agdturner@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
/** version from package.json, to be filled in during deployment */
|
||||
const VERSION = '__MOLSTAR_VERSION__';
|
||||
|
||||
const CACHE_NAME = `molstar-viewer-${VERSION}`;
|
||||
|
||||
// The static resources that the app needs to function.
|
||||
const APP_STATIC_RESOURCES = [
|
||||
'favicon.ico',
|
||||
'index.html',
|
||||
'molstar.css',
|
||||
'molstar.js',
|
||||
'manifest.webmanifest',
|
||||
'logo-144.png',
|
||||
'pwa.js'
|
||||
];
|
||||
|
||||
async function cacheStaticResources() {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
await cache.addAll(APP_STATIC_RESOURCES);
|
||||
await self.skipWaiting(); // Ensures the new service worker takes control immediately.
|
||||
}
|
||||
|
||||
async function deleteOldCaches() {
|
||||
const keys = await caches.keys();
|
||||
await Promise.all(
|
||||
keys.map((key) => {
|
||||
if (key !== CACHE_NAME) {
|
||||
return caches.delete(key);
|
||||
}
|
||||
}),
|
||||
);
|
||||
await self.clients.claim(); // Ensures the new service worker takes control immediately.
|
||||
}
|
||||
|
||||
async function respondWithCacheFirst(request) {
|
||||
// Try to match the request with the cache
|
||||
const cachedResponse = await caches.match(request);
|
||||
return cachedResponse || fetch(request);
|
||||
}
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
// console.log(`Service Worker version ${VERSION} installed.`);
|
||||
event.waitUntil(cacheStaticResources());
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
// console.log(`Service Worker version ${VERSION} activated.`);
|
||||
event.waitUntil(deleteOldCaches());
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
event.respondWith(respondWithCacheFirst(event.request));
|
||||
});
|
||||
@@ -20,7 +20,7 @@
|
||||
"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,webmanifest,png}\" lib/ && cpx \"src/**/sw.js\" lib/",
|
||||
"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\"",
|
||||
@@ -28,7 +28,7 @@
|
||||
"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,webmanifest,png}\" lib/ --watch && cpx \"src/**/sw.js\" lib/ --watch",
|
||||
"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",
|
||||
@@ -134,7 +134,6 @@
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^9.1.2",
|
||||
"copy-webpack-plugin": "^13.0.0",
|
||||
"cpx2": "^8.0.0",
|
||||
"crypto-browserify": "^3.12.1",
|
||||
"css-loader": "^7.1.2",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -9,7 +9,10 @@ const path = require('path');
|
||||
const fs = require("fs");
|
||||
const fse = require("fs-extra");
|
||||
|
||||
const VERSION = require(path.resolve(__dirname, '../package.json')).version;
|
||||
|
||||
const remoteUrl = "https://github.com/molstar/molstar.github.io.git";
|
||||
const dataDir = path.resolve(__dirname, '../data/');
|
||||
const buildDir = path.resolve(__dirname, '../build/');
|
||||
const deployDir = path.resolve(buildDir, 'deploy/');
|
||||
const localPath = path.resolve(deployDir, 'molstar.github.io/');
|
||||
@@ -17,6 +20,12 @@ const localPath = path.resolve(deployDir, 'molstar.github.io/');
|
||||
const analyticsTag = /<!-- __MOLSTAR_ANALYTICS__ -->/g;
|
||||
const analyticsCode = `<!-- Cloudflare Web Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "c414cbae2d284ea995171a81e4a3e721"}'></script><!-- End Cloudflare Web Analytics --><iframe src="https://web3dsurvey.com/collector-iframe.html" style="width: 1px; height: 1px;"></iframe>`;
|
||||
|
||||
const manifestTag = /<!-- __MOLSTAR_MANIFEST__ -->/g;
|
||||
const manifestCode = `<link rel="manifest" href="./manifest.webmanifest">`;
|
||||
|
||||
const pwaTag = /<!-- __MOLSTAR_PWA__ -->/g;
|
||||
const pwaCode = `<script src='./pwa.js'></script>`;
|
||||
|
||||
function log(command, stdout, stderr) {
|
||||
if (command) {
|
||||
console.log('\n###', command);
|
||||
@@ -31,17 +40,41 @@ function addAnalytics(path) {
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function addManifest(path) {
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const result = data.replace(manifestTag, manifestCode);
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function addPwa(path) {
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const result = data.replace(pwaTag, pwaCode);
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function addVersion(path) {
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const result = data.replace('__MOLSTAR_VERSION__', VERSION);
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function copyViewer() {
|
||||
console.log('\n###', 'copy viewer files');
|
||||
const viewerBuildPath = path.resolve(buildDir, '../build/viewer/');
|
||||
const viewerBuildPath = path.resolve(buildDir, 'viewer/');
|
||||
const viewerDeployPath = path.resolve(localPath, 'viewer/');
|
||||
fse.copySync(viewerBuildPath, viewerDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(viewerDeployPath, 'index.html'));
|
||||
addManifest(path.resolve(viewerDeployPath, 'index.html'));
|
||||
addPwa(path.resolve(viewerDeployPath, 'index.html'));
|
||||
|
||||
const pwaDataPath = path.resolve(dataDir, 'pwa/');
|
||||
fse.copySync(pwaDataPath, viewerDeployPath, { overwrite: true });
|
||||
addVersion(path.resolve(viewerDeployPath, 'sw.js'));
|
||||
}
|
||||
|
||||
function copyMe() {
|
||||
console.log('\n###', 'copy me files');
|
||||
const meBuildPath = path.resolve(buildDir, '../build/mesoscale-explorer/');
|
||||
const meBuildPath = path.resolve(buildDir, 'mesoscale-explorer/');
|
||||
const meDeployPath = path.resolve(localPath, 'me/viewer/');
|
||||
fse.copySync(meBuildPath, meDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(meDeployPath, 'index.html'));
|
||||
@@ -49,12 +82,12 @@ function copyMe() {
|
||||
|
||||
function copyDemos() {
|
||||
console.log('\n###', 'copy demos files');
|
||||
const lightingBuildPath = path.resolve(buildDir, '../build/examples/lighting/');
|
||||
const lightingBuildPath = path.resolve(buildDir, 'examples/lighting/');
|
||||
const lightingDeployPath = path.resolve(localPath, 'demos/lighting/');
|
||||
fse.copySync(lightingBuildPath, lightingDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(lightingDeployPath, 'index.html'));
|
||||
|
||||
const orbitalsBuildPath = path.resolve(buildDir, '../build/examples/alpha-orbitals/');
|
||||
const orbitalsBuildPath = path.resolve(buildDir, 'examples/alpha-orbitals/');
|
||||
const orbitalsDeployPath = path.resolve(localPath, 'demos/alpha-orbitals/');
|
||||
fse.copySync(orbitalsBuildPath, orbitalsDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(orbitalsDeployPath, 'index.html'));
|
||||
|
||||
@@ -61,7 +61,7 @@ import { ObjectKeys } from '../../mol-util/type-helpers';
|
||||
import { OpenFiles } from '../../mol-plugin-state/actions/file';
|
||||
|
||||
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
|
||||
export { consoleStats, setDebugMode, setProductionMode, setTimingMode } from '../../mol-util/debug';
|
||||
export { consoleStats, setDebugMode, setProductionMode, setTimingMode, isProductionMode, isDebugMode, isTimingMode } from '../../mol-util/debug';
|
||||
|
||||
const CustomFormats = [
|
||||
['g3d', G3dProvider] as const
|
||||
@@ -561,14 +561,14 @@ export class Viewer {
|
||||
}
|
||||
}
|
||||
|
||||
async loadFiles(files: File[]) {
|
||||
loadFiles(files: File[]) {
|
||||
const sessions = files.filter(f => {
|
||||
const fn = f.name.toLowerCase();
|
||||
return fn.endsWith('.molx') || fn.endsWith('.molj');
|
||||
});
|
||||
|
||||
if (sessions.length > 0) {
|
||||
PluginCommands.State.Snapshots.OpenFile(this.plugin, { file: sessions[0] });
|
||||
return PluginCommands.State.Snapshots.OpenFile(this.plugin, { file: sessions[0] });
|
||||
} else {
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(OpenFiles, {
|
||||
files: files.map(f => Asset.File(f)),
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
<link rel="manifest" href="./manifest.webmanifest">
|
||||
<!-- __MOLSTAR_MANIFEST__ -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
@@ -132,37 +132,11 @@
|
||||
viewer.dispose();
|
||||
});
|
||||
|
||||
// Handle incoming files
|
||||
if ('launchQueue' in window) {
|
||||
launchQueue.setConsumer((launchParams) => {
|
||||
if (!launchParams.files.length) return;
|
||||
|
||||
const files = [];
|
||||
for (const fileHandle of launchParams.files) {
|
||||
files.push(fileHandle.getFile());
|
||||
}
|
||||
|
||||
Promise.all(files).then((files) => {
|
||||
viewer.loadFiles(files);
|
||||
});
|
||||
});
|
||||
}
|
||||
const event = new CustomEvent("molstarViewerCreated", { detail: { viewer } });
|
||||
window.dispatchEvent(event);
|
||||
});
|
||||
|
||||
// Register Progressive Web App service worker.
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', function () {
|
||||
navigator.serviceWorker.register('./sw.js')
|
||||
.then(function (registration) {
|
||||
// Registration was successful
|
||||
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
||||
}, function (err) {
|
||||
// registration failed :(
|
||||
console.log('ServiceWorker registration failed: ', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<!-- __MOLSTAR_PWA__ -->
|
||||
<!-- __MOLSTAR_ANALYTICS__ -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 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>
|
||||
@@ -8,7 +8,5 @@
|
||||
import './embedded.html';
|
||||
import './favicon.ico';
|
||||
import './index.html';
|
||||
import './manifest.webmanifest';
|
||||
import './logo-144.png';
|
||||
import '../../mol-plugin-ui/skin/light.scss';
|
||||
export * from './app';
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Andy Turner <agdturner@gmail.com>
|
||||
*
|
||||
* @description Service worker for the viewer app.
|
||||
* The service worker:
|
||||
* - caches the static resources that the app needs to function
|
||||
* - intercepts server requests and responds with cached responses instead of going to the network
|
||||
* - deletes old caches on activation
|
||||
* - responds with cached resources on fetch
|
||||
* - responds with a network error if fetching fails
|
||||
* - responds with a cache error if the cache match fails
|
||||
*
|
||||
* To not complicate the build process, this file is not transpiled but written in JavaScript.
|
||||
* It is coppied to the build directory as is and no imports must be used.
|
||||
*/
|
||||
|
||||
/** version from package.json, to be filled in at build time */
|
||||
const VERSION = '';
|
||||
|
||||
const CACHE_NAME = `molstar-viewer-${VERSION}`;
|
||||
|
||||
// The static resources that the app needs to function.
|
||||
const APP_STATIC_RESOURCES = [
|
||||
'favicon.ico',
|
||||
'index.html',
|
||||
'molstar.css',
|
||||
'molstar.js',
|
||||
'manifest.webmanifest',
|
||||
'logo-144.png'
|
||||
];
|
||||
|
||||
// On install, cache the static resources.
|
||||
self.addEventListener('install', (event) => {
|
||||
console.log(`Service Worker version ${VERSION} installed.`);
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
await cache.addAll(APP_STATIC_RESOURCES);
|
||||
await self.skipWaiting(); // Ensures the new service worker takes control immediately.
|
||||
})(),
|
||||
);
|
||||
});
|
||||
|
||||
// On activate, delete old caches.
|
||||
self.addEventListener('activate', (event) => {
|
||||
console.log(`Service Worker version ${VERSION} activated.`);
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
const keys = await caches.keys();
|
||||
await Promise.all(
|
||||
keys.map((key) => {
|
||||
if (key !== CACHE_NAME) {
|
||||
return caches.delete(key);
|
||||
}
|
||||
}),
|
||||
);
|
||||
await self.clients.claim(); // Ensures the new service worker takes control immediately.
|
||||
})(),
|
||||
);
|
||||
});
|
||||
|
||||
// On fetch, respond with cached resources.
|
||||
self.addEventListener('fetch', (event) => {
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
try {
|
||||
// Try to match the request with the cache
|
||||
const cachedResponse = await caches.match(event.request);
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
// Fetch from network if not found in cache
|
||||
const networkResponse = await fetch(event.request);
|
||||
// Check if the network response is valid
|
||||
if (!networkResponse || networkResponse.status !== 200 || networkResponse.type !== 'basic') {
|
||||
return networkResponse;
|
||||
}
|
||||
// Clone the network response
|
||||
const responseToCache = networkResponse.clone();
|
||||
// Open the cache and put the network response in it
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
await cache.put(event.request, responseToCache);
|
||||
return networkResponse;
|
||||
} catch (error) {
|
||||
console.error('Fetching failed:', error);
|
||||
return new Response('Network error occurred', {
|
||||
status: 408,
|
||||
statusText: 'Network error occurred'
|
||||
});
|
||||
}
|
||||
})()
|
||||
);
|
||||
});
|
||||
@@ -3,7 +3,6 @@ const fs = require('fs');
|
||||
const webpack = require('webpack');
|
||||
const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const VERSION = require('./package.json').version;
|
||||
|
||||
class VersionFilePlugin {
|
||||
@@ -14,8 +13,31 @@ class VersionFilePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
function getSharedConfig(copyPluginPatterns) {
|
||||
const plugins = [
|
||||
const sharedConfig = {
|
||||
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',
|
||||
@@ -28,73 +50,40 @@ function getSharedConfig(copyPluginPatterns) {
|
||||
}),
|
||||
new MiniCssExtractPlugin({ filename: 'molstar.css' }),
|
||||
new VersionFilePlugin(),
|
||||
];
|
||||
|
||||
if (copyPluginPatterns && copyPluginPatterns.length > 0) {
|
||||
plugins.push(new CopyPlugin({
|
||||
patterns: copyPluginPatterns,
|
||||
}));
|
||||
}
|
||||
|
||||
return {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(html|ico|webmanifest|png)$/,
|
||||
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: plugins,
|
||||
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
|
||||
],
|
||||
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}`) },
|
||||
...getSharedConfig()
|
||||
...sharedConfig
|
||||
};
|
||||
}
|
||||
|
||||
function createEntryPoint(name, dir, out, library, copyPluginPatterns) {
|
||||
function createEntryPoint(name, dir, out, library) {
|
||||
return {
|
||||
entry: path.resolve(__dirname, `lib/${dir}/${name}.js`),
|
||||
output: { filename: `${library || name}.js`, path: path.resolve(__dirname, `build/${out}`), library: library || out, libraryTarget: 'umd', assetModuleFilename: 'images/[hash][ext][query]', 'publicPath': '' },
|
||||
...getSharedConfig(copyPluginPatterns)
|
||||
...sharedConfig
|
||||
};
|
||||
}
|
||||
|
||||
@@ -109,11 +98,11 @@ function createNodeEntryPoint(name, dir, out) {
|
||||
'util.promisify': 'require("util.promisify")',
|
||||
xhr2: 'require("xhr2")',
|
||||
},
|
||||
...getSharedConfig()
|
||||
...sharedConfig
|
||||
};
|
||||
}
|
||||
|
||||
function createApp(name, library, copyPluginPatterns) { return createEntryPoint('index', `apps/${name}`, name, library, copyPluginPatterns); }
|
||||
function createApp(name, library) { return createEntryPoint('index', `apps/${name}`, name, library); }
|
||||
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); }
|
||||
@@ -125,4 +114,4 @@ module.exports = {
|
||||
createBrowserTest,
|
||||
createNodeEntryPoint,
|
||||
createNodeApp
|
||||
};
|
||||
};
|
||||
@@ -1,14 +1,6 @@
|
||||
const common = require('./webpack.config.common.js');
|
||||
const VERSION = require('./package.json').version;
|
||||
const createApp = common.createApp;
|
||||
module.exports = (env, argv) => {
|
||||
return [
|
||||
createApp('viewer', 'molstar', [{
|
||||
from: 'lib/apps/viewer/sw.js',
|
||||
transform: (content) => {
|
||||
return content.toString().replace('const VERSION = \'\';', `const VERSION = '${VERSION}${env.WEBPACK_WATCH ? '-' + new Date().valueOf() : ''}';`);
|
||||
}
|
||||
}]),
|
||||
createApp('mesoscale-explorer', 'molstar'),
|
||||
];
|
||||
};
|
||||
module.exports = [
|
||||
createApp('viewer', 'molstar'),
|
||||
createApp('mesoscale-explorer', 'molstar'),
|
||||
];
|
||||
Reference in New Issue
Block a user