mirror of
https://github.com/psychopy/psychojs.git
synced 2025-05-10 18:50:54 +00:00
213 lines
5.0 KiB
JavaScript
213 lines
5.0 KiB
JavaScript
// ES native imports courtesy of using type module in 'package.json'
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { minify } from 'terser';
|
|
import babel from '@rollup/plugin-babel';
|
|
import pkg from './package.json';
|
|
|
|
// Manually set default version here for easier
|
|
// diffing when comparing to original build script output
|
|
const { VERSION: version = pkg.version } = process.env;
|
|
|
|
// Enabled in the original, even though
|
|
// source maps missing for sample provided
|
|
const sourcemap = false;
|
|
|
|
// Might be 'build' or similar
|
|
const destination = './dist';
|
|
|
|
// Could be 'src' or 'lib'
|
|
const source = './src';
|
|
|
|
// Start fresh
|
|
try {
|
|
if (fs.existsSync(destination)) {
|
|
// Clear out JS files before rebuilding
|
|
const contents = fs.readdirSync(destination).filter(item => item.endsWith('js'));
|
|
|
|
for (const item of contents) {
|
|
const target = path.join(destination, item);
|
|
const stat = fs.statSync(target);
|
|
|
|
// Delete
|
|
fs.unlinkSync(target);
|
|
}
|
|
} else {
|
|
// Create 'dist' if missing
|
|
fs.mkdirSync(destination);
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
|
|
// For sorting legacy/IE11 bundle components
|
|
const orderOfAppearance = [ 'util', 'data', 'core', 'visual', 'sound' ];
|
|
const last = [ ...orderOfAppearance ].pop();
|
|
const footer = `
|
|
// Add a few top level variables for convenience, this makes it
|
|
// possible to eg. use "return Scheduler.Event.NEXT;" instead of "util.Scheduler.Event.NEXT;"
|
|
PsychoJS = core.PsychoJS;
|
|
TrialHandler = data.TrialHandler;
|
|
Scheduler = util.Scheduler;`;
|
|
|
|
const plugins = [
|
|
babel({
|
|
babelHelpers: 'bundled',
|
|
exclude: 'node_modules/**',
|
|
include: `${destination}/*.iife.js`
|
|
}),
|
|
minifier({
|
|
compress: false,
|
|
mangle: false,
|
|
output: {
|
|
beautify: true
|
|
},
|
|
sourceMap: false,
|
|
toplevel: false
|
|
})
|
|
];
|
|
|
|
// List source directory contents
|
|
const components = fs.readdirSync(source)
|
|
// Need subdirectories only
|
|
.filter((item) => {
|
|
const target = path.join(source, item);
|
|
const stat = fs.statSync(target);
|
|
|
|
return stat.isDirectory();
|
|
})
|
|
// Put in order
|
|
.sort((a, b) => orderOfAppearance.indexOf(a) - orderOfAppearance.indexOf(b))
|
|
// Prepare an output object for each component module
|
|
.map((component, _, contents) => ({
|
|
// So I don't have to specify full paths
|
|
external: (id) => {
|
|
// Decompose current component path
|
|
const segments = id.split('/');
|
|
|
|
// Mark as external if contents within source
|
|
// directory tree, excluding the current component
|
|
return contents
|
|
.filter(item => item !== component)
|
|
.some(item => segments.includes(item));
|
|
},
|
|
input: `${source}/${component}/index.js`,
|
|
// Disable circular dependency warnings
|
|
onwarn,
|
|
output: [
|
|
{
|
|
file: `${destination}/${component}-${version}.js`,
|
|
format: 'module',
|
|
globals: {
|
|
performance: 'performance'
|
|
},
|
|
// Find which module the import points to
|
|
// and fix path in place
|
|
paths: (id) => {
|
|
const name = findName(id, contents);
|
|
|
|
return `./${name}-${version}.js`;
|
|
},
|
|
sourcemap,
|
|
},
|
|
{
|
|
esModule: false,
|
|
file: `${destination}/${component}-${version}.iife.js`,
|
|
format: 'iife',
|
|
globals: id => findName(id, contents),
|
|
name: component,
|
|
paths: (id) => {
|
|
const name = findName(id, contents);
|
|
|
|
return `./${name}-${version}.iife.js`;
|
|
},
|
|
sourcemap,
|
|
plugins: [
|
|
appender({
|
|
target: `${destination}/psychojs-${version}.js`,
|
|
// Mirrors rollup's 'outputOptions' hook
|
|
outputOptions: (options) => {
|
|
if (options.file.includes(last)) {
|
|
options.footer = footer;
|
|
}
|
|
|
|
return options;
|
|
}
|
|
})
|
|
]
|
|
}
|
|
],
|
|
plugins
|
|
})
|
|
);
|
|
|
|
export default [
|
|
...components,
|
|
{
|
|
// Add a UMD build for Thomas
|
|
input: `${source}/index.js`,
|
|
onwarn,
|
|
output: {
|
|
file: `${destination}/psychojs-${version}.umd.js`,
|
|
format: 'umd',
|
|
name: 'psychojs'
|
|
},
|
|
plugins
|
|
}
|
|
];
|
|
|
|
// https://rollupjs.org/guide/en/#onwarn
|
|
function onwarn(message, warn) {
|
|
// Skip circular dependency warnings
|
|
if (message.code === 'CIRCULAR_DEPENDENCY') {
|
|
return;
|
|
}
|
|
|
|
warn(message);
|
|
}
|
|
|
|
// Helper for extracting module name from contents array by rollup id (path to file)
|
|
function findName(id, contents) {
|
|
return id.split(path.sep).find(item => contents.includes(item));
|
|
}
|
|
|
|
// Minimal terser plugin
|
|
function minifier(options) {
|
|
return {
|
|
name: 'minifier',
|
|
async renderChunk(code) {
|
|
try {
|
|
// Includes code and map keys
|
|
const result = await minify(code, options);
|
|
|
|
return result;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Custom plugin for cancatenating IIFE's sans cat(1)
|
|
function appender({ target = '', outputOptions = () => {} } = {}) {
|
|
return {
|
|
name: 'appender',
|
|
outputOptions: (options) => outputOptions(options),
|
|
async generateBundle(options, bundle) {
|
|
const { file } = options;
|
|
const id = file.split('/').pop();
|
|
const { code } = bundle[id];
|
|
|
|
// Should be expected to throw if `target` missing
|
|
fs.appendFile(target, code, (error) => {
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// Prevent write out
|
|
delete bundle[id];
|
|
}
|
|
};
|
|
}
|