mirror of
https://github.com/google/blockly.git
synced 2026-01-09 10:00:09 +01:00
Add local build tasks to gulp (#2895)
* Support compiling from the npm closure compiler and add gulp tasks
This commit is contained in:
298
gulpfile.js
298
gulpfile.js
@@ -36,15 +36,295 @@ var fs = require('fs');
|
||||
var rimraf = require('rimraf');
|
||||
var execSync = require('child_process').execSync;
|
||||
|
||||
// Rebuilds Blockly, including the following:
|
||||
// - blockly_compressed.js
|
||||
// - blocks_compressed.js
|
||||
// - Localization string tables in msg/js/*.js
|
||||
// - Generators in generators/*.js
|
||||
// These files are already up-to-date in the master branch.
|
||||
gulp.task('build', gulp.shell.task([
|
||||
'python build.py'
|
||||
]));
|
||||
var closureCompiler = require('google-closure-compiler').gulp();
|
||||
var packageJson = require('./package.json');
|
||||
var argv = require('yargs').argv;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Build //
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
const licenseRegex = `\\/\\*\\*
|
||||
\\* @license
|
||||
\\* [\\w: ]+
|
||||
\\*
|
||||
\\* (Copyright \\d+ (Google Inc.|Massachusetts Institute of Technology))
|
||||
\\* (https://developers.google.com/blockly/|All rights reserved.)
|
||||
\\*
|
||||
\\* Licensed under the Apache License, Version 2.0 \\(the "License"\\);
|
||||
\\* you may not use this file except in compliance with the License.
|
||||
\\* You may obtain a copy of the License at
|
||||
\\*
|
||||
\\* http://www.apache.org/licenses/LICENSE-2.0
|
||||
\\*
|
||||
\\* Unless required by applicable law or agreed to in writing, software
|
||||
\\* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
\\* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
\\* See the License for the specific language governing permissions and
|
||||
\\* limitations under the License.
|
||||
\\*\\/`;
|
||||
|
||||
/**
|
||||
* Helper method for stripping the Google's and MIT's Apache Licenses.
|
||||
*/
|
||||
function stripApacheLicense() {
|
||||
// Strip out Google's and MIT's Apache licences.
|
||||
// Closure Compiler preserves dozens of Apache licences in the Blockly code.
|
||||
// Remove these if they belong to Google or MIT.
|
||||
// MIT's permission to do this is logged in Blockly issue #2412.
|
||||
return gulp.replace(new RegExp(licenseRegex, "g"), '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for prepending the auto-generated header text.
|
||||
*/
|
||||
function prependHeader() {
|
||||
return gulp.insert.prepend(`// Do not edit this file; automatically generated by gulp.\n`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for calling the Closure compiler.
|
||||
* @param {*} compilerOptions
|
||||
* @param {boolean=} opt_verbose Optional option for verbose logging
|
||||
*/
|
||||
function compile(compilerOptions, opt_verbose) {
|
||||
if (!compilerOptions) compilerOptions = {};
|
||||
compilerOptions.compilation_level = 'SIMPLE_OPTIMIZATIONS';
|
||||
compilerOptions.warning_level = opt_verbose ? 'VERBOSE' : 'DEFAULT';
|
||||
compilerOptions.language_out = 'ECMASCRIPT5_STRICT';
|
||||
compilerOptions.rewrite_polyfills = false;
|
||||
compilerOptions.generate_exports = true;
|
||||
compilerOptions.hide_warnings_for = 'node_modules';
|
||||
|
||||
const platform = ['native', 'java', 'javascript'];
|
||||
|
||||
return closureCompiler(compilerOptions, { platform });
|
||||
}
|
||||
|
||||
/**
|
||||
* This task builds Blockly's core files.
|
||||
* blockly_compressed.js
|
||||
*/
|
||||
gulp.task('build-core', function () {
|
||||
const defines = 'Blockly.VERSION="' + packageJson.version + '"';
|
||||
return gulp.src([
|
||||
'core/**/**/*.js',
|
||||
'./node_modules/google-closure-library/closure/goog/base.js'
|
||||
], {base: './'})
|
||||
// Directories in Blockly are used to group similar files together
|
||||
// but are not used to limit access with @package, instead the
|
||||
// method means something is internal to Blockly and not a public
|
||||
// API.
|
||||
// Flatten all files so they're in the same directory, but ensure that
|
||||
// files with the same name don't conflict.
|
||||
.pipe(gulp.rename(function (p) {
|
||||
var dirname = p.dirname.replace(new RegExp(path.sep, "g"), "-");
|
||||
p.dirname = "";
|
||||
p.basename = dirname + "-" + p.basename;
|
||||
}))
|
||||
.pipe(stripApacheLicense())
|
||||
.pipe(compile({
|
||||
dependency_mode: 'PRUNE',
|
||||
entry_point: './core-blockly.js',
|
||||
js_output_file: 'blockly_compressed.js',
|
||||
externs: './externs/svg-externs.js',
|
||||
define: defines
|
||||
}, argv.verbose))
|
||||
.pipe(prependHeader())
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
|
||||
/**
|
||||
* This task builds the Blockly's built in blocks.
|
||||
* blocks_compressed.js
|
||||
*/
|
||||
gulp.task('build-blocks', function () {
|
||||
const provides = `goog.provide('Blockly');\ngoog.provide('Blockly.Blocks');\n`;
|
||||
return gulp.src('blocks/*.js', {base: './'})
|
||||
// Add Blockly.Blocks to be compatible with the compiler.
|
||||
.pipe(gulp.replace(`goog.provide('Blockly.Constants.Colour');`,
|
||||
`${provides}goog.provide('Blockly.Constants.Colour');`))
|
||||
.pipe(stripApacheLicense())
|
||||
.pipe(compile({
|
||||
dependency_mode: 'NONE',
|
||||
js_output_file: 'blocks_compressed.js'
|
||||
}, argv.verbose))
|
||||
.pipe(gulp.replace('\'use strict\';', '\'use strict\';\n\n\n'))
|
||||
// Remove Blockly.Blocks to be compatible with Blockly.
|
||||
.pipe(gulp.replace('var Blockly={Blocks:{}};', ''))
|
||||
.pipe(prependHeader())
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
|
||||
/**
|
||||
* A helper method for building a Blockly code generator.
|
||||
* @param {string} language Generator language.
|
||||
* @param {string} namespace Language namespace.
|
||||
*/
|
||||
function buildGenerator(language, namespace) {
|
||||
var provides = `goog.provide('Blockly.Generator');\ngoog.provide('Blockly.utils.string');\n`;
|
||||
return gulp.src([`generators/${language}.js`, `generators/${language}/*.js`], {base: './'})
|
||||
.pipe(stripApacheLicense())
|
||||
// Add Blockly.Generator and Blockly.utils.string to be compatible with the compiler.
|
||||
.pipe(gulp.replace(`goog.provide('Blockly.${namespace}');`,
|
||||
`${provides}goog.provide('Blockly.${namespace}');`))
|
||||
.pipe(compile({
|
||||
dependency_mode: 'NONE',
|
||||
js_output_file: `${language}_compressed.js`
|
||||
}, argv.verbose))
|
||||
.pipe(gulp.replace('\'use strict\';', '\'use strict\';\n\n\n'))
|
||||
// Remove Blockly.Generator and Blockly.utils.string to be compatible with Blockly.
|
||||
.pipe(gulp.replace('var Blockly={Generator:{},utils:{}};Blockly.utils.string={};', ''))
|
||||
.pipe(prependHeader())
|
||||
.pipe(gulp.dest('./'));
|
||||
};
|
||||
|
||||
/**
|
||||
* This task builds the javascript generator.
|
||||
* javascript_compressed.js
|
||||
*/
|
||||
gulp.task('build-javascript', function() {
|
||||
return buildGenerator('javascript', 'JavaScript');
|
||||
});
|
||||
|
||||
/**
|
||||
* This task builds the python generator.
|
||||
* python_compressed.js
|
||||
*/
|
||||
gulp.task('build-python', function() {
|
||||
return buildGenerator('python', 'Python');
|
||||
});
|
||||
|
||||
/**
|
||||
* This task builds the php generator.
|
||||
* php_compressed.js
|
||||
*/
|
||||
gulp.task('build-php', function() {
|
||||
return buildGenerator('php', 'PHP');
|
||||
});
|
||||
|
||||
/**
|
||||
* This task builds the lua generator.
|
||||
* lua_compressed.js
|
||||
*/
|
||||
gulp.task('build-lua', function() {
|
||||
return buildGenerator('lua', 'Lua');
|
||||
});
|
||||
|
||||
/**
|
||||
* This task builds the dart generator:
|
||||
* dart_compressed.js
|
||||
*/
|
||||
gulp.task('build-dart', function() {
|
||||
return buildGenerator('dart', 'Dart');
|
||||
});
|
||||
|
||||
/**
|
||||
* This task builds Blockly's uncompressed file.
|
||||
* blockly_uncompressed.js
|
||||
*/
|
||||
gulp.task('build-uncompressed', function() {
|
||||
const header = `// Do not edit this file; automatically generated by build.py.
|
||||
'use strict';
|
||||
|
||||
this.IS_NODE_JS = !!(typeof module !== 'undefined' && module.exports);
|
||||
|
||||
this.BLOCKLY_DIR = (function(root) {
|
||||
if (!root.IS_NODE_JS) {
|
||||
// Find name of current directory.
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
var re = new RegExp('(.+)[\\\/]blockly_(.*)uncompressed\\\.js$');
|
||||
for (var i = 0, script; script = scripts[i]; i++) {
|
||||
var match = re.exec(script.src);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
||||
alert('Could not detect Blockly\\'s directory name.');
|
||||
}
|
||||
return '';
|
||||
})(this);
|
||||
|
||||
this.BLOCKLY_BOOT = function(root) {
|
||||
var dir = '';
|
||||
if (root.IS_NODE_JS) {
|
||||
dir = 'blockly';
|
||||
} else {
|
||||
dir = this.BLOCKLY_DIR.match(/[^\\/]+$/)[0];
|
||||
}
|
||||
// Execute after Closure has loaded.
|
||||
`;
|
||||
const footer = `
|
||||
delete root.BLOCKLY_DIR;
|
||||
delete root.BLOCKLY_BOOT;
|
||||
delete root.IS_NODE_JS;
|
||||
};
|
||||
|
||||
if (this.IS_NODE_JS) {
|
||||
this.BLOCKLY_BOOT(this);
|
||||
module.exports = Blockly;
|
||||
} else {
|
||||
// Delete any existing Closure (e.g. Soy's nogoog_shim).
|
||||
document.write('<script>var goog = undefined;</script>');
|
||||
// Load fresh Closure Library.
|
||||
document.write('<script src="' + this.BLOCKLY_DIR +
|
||||
'/closure-library/base.js"></script>');
|
||||
document.write('<script>this.BLOCKLY_BOOT(this);</script>');
|
||||
}
|
||||
`;
|
||||
const file = 'blockly_uncompressed.js';
|
||||
// Run depswriter.py and which scans the core directory and writes out a ``goog.addDependency`` line for each file.
|
||||
const cmd = `python ./node_modules/google-closure-library/closure/bin/build/depswriter.py \
|
||||
--root_with_prefix="./core ../core" > ${file}`;
|
||||
execSync(cmd, { stdio: 'inherit' });
|
||||
|
||||
let providesBuilder = `\n// Load Blockly.\n`;
|
||||
const provides = new Set();
|
||||
const dependencies = fs.readFileSync(file, "utf8");
|
||||
const re = /\'(Blockly[^\']*)\'/gi;
|
||||
let m;
|
||||
while (m = re.exec(dependencies)) {
|
||||
provides.add(`goog.require('${m[1]}');`);
|
||||
}
|
||||
providesBuilder += Array.from(provides).sort().join('\n') + '\n';
|
||||
|
||||
return gulp.src(file)
|
||||
// Remove comments so we're compatible with the build.py script
|
||||
.pipe(gulp.replace(/\/\/.*\n/gm, ''))
|
||||
// Replace quotes to be compatible with build.py
|
||||
.pipe(gulp.replace(/\'(.*\.js)\'/gm, '"$1"'))
|
||||
// Find the Blockly directory name and replace it with a JS variable.
|
||||
// This allows blockly_uncompressed.js to be compiled on one computer and be
|
||||
// used on another, even if the directory name differs.
|
||||
.pipe(gulp.replace(/\.\.\/core/gm, `../../" + dir + "/core`))
|
||||
.pipe(gulp.insert.wrap(header, providesBuilder + footer))
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
|
||||
/**
|
||||
* This task builds all of Blockly:
|
||||
* blockly_compressed.js
|
||||
* blocks_compressed.js
|
||||
* javascript_compressed.js
|
||||
* python_compressed.js
|
||||
* php_compressed.js
|
||||
* lua_compressed.js
|
||||
* dart_compressed.js
|
||||
*/
|
||||
gulp.task('build', gulp.parallel(
|
||||
'build-core',
|
||||
'build-blocks',
|
||||
'build-javascript',
|
||||
'build-python',
|
||||
'build-php',
|
||||
'build-lua',
|
||||
'build-dart'
|
||||
));
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Node //
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Concatenates the necessary files to load Blockly in a Node.js VM. Blockly's
|
||||
// individual libraries target use in a browser, where globals (via the window
|
||||
|
||||
Reference in New Issue
Block a user