const path = require('path'); const fs = require('fs-extra'); const commandLineArgs = require('command-line-args'); const rollup = require('rollup'); const babel = require('@rollup/plugin-babel').default; const commonjs = require('@rollup/plugin-commonjs'); const nodeResolve = require('@rollup/plugin-node-resolve').default; const nodeBuiltins = require('rollup-plugin-node-builtins'); const nodeGlobals = require('rollup-plugin-node-globals'); const importImage = require('@rollup/plugin-image'); const multi = require('@rollup/plugin-multi-entry'); const optionDefinitions = [ { name: 'name', type: String }, { name: 'url', type: String }, { name: 'block', type: String }, { name: 'entry', type: String }, { name: 'vm', type:String }, { name: 'gui', type:String, defaultValue: '../scratch-gui' }, { name: 'output', type:String, defaultValue: './build' }, { name: 'debug', type:Boolean } ]; // Read options const options = commandLineArgs(optionDefinitions); if (!options['name']) { throw('set --name '); } const moduleName = options['name']; if (!options['block']) { throw('set --block '); } const extSrcDir = path.resolve(process.cwd(), options['block']); if (!options['entry']) { throw('set --entry '); } const entrySrcDir = path.resolve(process.cwd(), options['entry']); const GuiRoot = path.resolve(process.cwd(), options['gui']); console.log(`gui = ${GuiRoot}`); const VmRoot = options['vm'] ? path.resolve(process.cwd(), options['vm']): path.resolve(GuiRoot, './node_modules/scratch-vm'); console.log(`vm = ${VmRoot}`); const outputDir = path.resolve(process.cwd(), options['output']); console.log(`output = ${outputDir}`); const blockWorkingDir = path.resolve(VmRoot, `src/extensions/_${moduleName}`); const blockFile = path.resolve(blockWorkingDir, 'index.js'); const entryWorkingDir = path.resolve(GuiRoot, `src/lib/libraries/extensions/_${moduleName}`); const entryFile = path.resolve(entryWorkingDir, 'index.jsx'); const moduleFile = path.resolve(outputDir, `${moduleName}.mjs`); const rollupOptions = { inputOptions: { input: [entryFile, blockFile], plugins: [ multi(), importImage(), nodeResolve({browser: true, preferBuiltins: true}), commonjs({ }), nodeBuiltins(), nodeGlobals(), babel({ babelrc: false, presets: [ ['@babel/preset-env', { "modules": false, targets: { browsers: [ 'last 3 versions', 'Safari >= 8', 'iOS >= 8'] } } ], '@babel/preset-react' ], babelHelpers: 'bundled', plugins: [ '@babel/plugin-transform-react-jsx' ] }), ] }, outputOptions: { file: moduleFile, format: 'es', } } async function build() { // Copy module sources fs.copySync(extSrcDir, blockWorkingDir); fs.copySync(entrySrcDir, entryWorkingDir); console.log('\ncopy source to working dir'); console.log(blockWorkingDir); console.log(entryWorkingDir); // Replace URL in entry and block code. if (options['url']) { const url = options['url']; // Replace URL in entry const entryFile = path.resolve(entryWorkingDir, './index.jsx'); let entryCode = fs.readFileSync(entryFile, 'utf-8'); entryCode = entryCode.replace(/extensionURL:\s*[^,]+,/m, `extensionURL: '${url}',`); fs.writeFileSync(entryFile, entryCode); console.log(`Entry: extensionURL = ${url}`); // Replace URL in entry const blockFile = path.resolve(blockWorkingDir, './index.js'); let blockCode = fs.readFileSync(blockFile, 'utf-8'); blockCode = blockCode.replace(/let\s+extensionURL\s+=\s+[^;]+;/m, `let extensionURL = '${url}';`); fs.writeFileSync(blockFile, blockCode); console.log(`Block: extensionURL = ${url}`); } // Build module. console.log('\nstart to build module ...'); const bundle = await rollup.rollup(rollupOptions.inputOptions); if (options['debug']) { console.log('\ncontent files\n----') bundle.watchFiles.forEach(fileName => console.log(fileName)); // an array of file names this bundle depends on console.log('----\n'); // show contents of the module bundle.generate(rollupOptions.outputOptions) .then(res => { for (const chunkOrAsset of res.output) { if (chunkOrAsset.type === 'asset') { console.log('Asset', chunkOrAsset); } else { console.log('Chunk', chunkOrAsset.modules); } } }) } // write the bundle to disk await bundle.write(rollupOptions.outputOptions); console.log(`\nsuccess to build module: ${moduleFile}`); // Clean up fs.removeSync(blockWorkingDir); fs.removeSync(entryWorkingDir); console.log('\nworking dir removed'); } try { build(); } catch (err) { console.error(err) }