From 72f1b363b15acd3da8f17273ff1f7e65b1f467af Mon Sep 17 00:00:00 2001 From: legendecas Date: Mon, 17 Feb 2020 12:06:18 +0800 Subject: [PATCH] feat(build): options to minify all products --- packages/midway-bin/lib/cmd/build.js | 74 +++++++++++++++++++ .../midway-bin/test/lib/cmd/build.test.js | 17 +++++ 2 files changed, 91 insertions(+) diff --git a/packages/midway-bin/lib/cmd/build.js b/packages/midway-bin/lib/cmd/build.js index 84797ad23791..26a5e0217af1 100644 --- a/packages/midway-bin/lib/cmd/build.js +++ b/packages/midway-bin/lib/cmd/build.js @@ -3,12 +3,16 @@ const Command = require('egg-bin').Command; const path = require('path'); const fs = require('fs'); +const fsPromise = fs.promises; const rimraf = require('mz-modules/rimraf'); const fse = require('fs-extra'); const globby = require('globby'); const ncc = require('@midwayjs/ncc'); +const typescript = require('typescript'); +const terser = require('terser'); const shebangRegEx = /^#![^\n\r]*[\r\n]/; +const inlineSourceMapRegEx = /\/\/# sourceMappingURL=data:application\/json;base64,(.*)/; class BuildCommand extends Command { constructor(rawArgv) { @@ -37,6 +41,9 @@ class BuildCommand extends Command { type: 'string', default: '', }, + minify: { + type: 'boolean', + }, mode: { description: 'bundle mode, "debug" or "release" (default)', type: 'string', @@ -94,6 +101,10 @@ class BuildCommand extends Command { args.push(argv.project); } await this.helper.forkNode(tscCli, args, { cwd, execArgv: [] }); + + if (argv.minify) { + await this.minify(tsConfig, outDirAbsolute); + } } async bundle(entry, outDir, { sourceMap = false, mode } = {}) { @@ -207,6 +218,69 @@ class BuildCommand extends Command { return tsConfig.compilerOptions[optionKeyPath]; } } + + async minify(tsConfig, outDir) { + const inlineSourceMap = !!tsConfig.compilerOptions.inlineSourceMap; + const sourceMap = inlineSourceMap || tsConfig.compilerOptions.sourceMap; + if (!sourceMap) { + return; + } + + let files; + if (outDir) { + files = globby.sync([ '**/*.js' ], { + cwd: outDir, + ignore: [ '**/node_modules' ], + }); + files = files.map(it => path.join(outDir, it)); + } else { + const host = typescript.createCompilerHost(tsConfig.compilerOptions); + files = host.readDirectory(__dirname, [ '.ts' ], tsConfig.exclude, tsConfig.include); + files = files.map(it => { + return path.join(path.dirname(it), path.basename(it, '.js')); + }); + } + + for (const file of files) { + let code = await fsPromise.readFile(file, 'utf8'); + let map; + if (inlineSourceMap) { + map = this.parseInlineSourceMap(code); + } else { + map = await fsPromise.readFile(file + '.map', 'utf8'); + } + map = JSON.parse(map); + const result = terser.minify(code, { + compress: false, + mangle: { + keep_classnames: true, + keep_fnames: true, + }, + sourceMap: { + content: map, + filename: path.basename(file), + url: inlineSourceMap ? 'inline' : `${path.basename(file)}.map`, + }, + }); + ({ code, map } = result); + if (code == null) { + break; + } + if (!inlineSourceMap) { + await fsPromise.writeFile(file + '.map', map, 'utf8'); + } + await fsPromise.writeFile(file, code, 'utf8'); + } + } + + parseInlineSourceMap(code) { + const match = inlineSourceMapRegEx.exec(code); + if (match == null) { + return; + } + const map = Buffer.from(match[1], 'base64').toString('utf8'); + return map; + } } module.exports = BuildCommand; diff --git a/packages/midway-bin/test/lib/cmd/build.test.js b/packages/midway-bin/test/lib/cmd/build.test.js index 9c83645dae80..73162ddf214b 100644 --- a/packages/midway-bin/test/lib/cmd/build.test.js +++ b/packages/midway-bin/test/lib/cmd/build.test.js @@ -170,3 +170,20 @@ describe('test/lib/cmd/build.test.js - bundling', () => { await rimraf(path.join(cwd, 'dist')); }); }); + +describe('test/lib/cmd/build.test.js - minify', () => { + const midwayBin = require.resolve('../../../bin/midway-bin.js'); + const argv = [ 'build', '-c', '--minify']; + + afterEach(mm.restore); + + it('should build success', async () => { + const cwd = path.join(__dirname, '../../fixtures/ts-dir'); + await rimraf(path.join(cwd, 'dist')); + const child = coffee.fork(midwayBin, argv, { cwd }); + await child.expect('code', 0).end(); + assert(fs.existsSync(path.join(cwd, 'dist/a.js'))); + assert(/\/\/# sourceMappingURL/.exec(fs.readFileSync(path.join(cwd, 'dist/a.js'), 'utf8'))); + await rimraf(path.join(cwd, 'dist')); + }); +});