Better messages for build commands (#5117)

* Better rollup messages in console

* Remove 'docs folder not found' warning

* Show production message

* fix codacy
This commit is contained in:
Faris Ansari 2018-03-05 22:07:55 +05:30 committed by Rushabh Mehta
parent 106944abc0
commit 55e5b473d0
9 changed files with 358 additions and 213 deletions

View file

@ -105,7 +105,8 @@ def make_asset_dirs(make_copy=False, restore=False):
shutil.rmtree(target)
os.symlink(source, target)
else:
warnings.warn('Source {source} does not exist.'.format(source = source))
# warnings.warn('Source {source} does not exist.'.format(source = source))
pass
def build(no_compress=False, verbose=False):
assets_path = os.path.join(frappe.local.sites_path, "assets")

View file

@ -1,9 +1,9 @@
{
"name": "frappe",
"scripts": {
"build": "rollup -c --silent",
"production": "FRAPPE_ENV=production rollup -c",
"watch": "rollup -c -w"
"build": "node rollup/build.js",
"production": "FRAPPE_ENV=production node rollup/build.js",
"watch": "node rollup/watch.js"
},
"repository": {
"type": "git",
@ -19,6 +19,7 @@
"cookie": "^0.3.1",
"express": "^4.16.2",
"frappe-datatable": "frappe/datatable",
"frappe-gantt": "^0.1.0",
"moment": "^2.20.1",
"redis": "^2.8.0",
"showdown": "^1.8.6",
@ -28,6 +29,7 @@
},
"devDependencies": {
"babel-runtime": "^6.26.0",
"chalk": "^2.3.2",
"rollup": "^0.55.3",
"rollup-plugin-buble": "^0.19.2",
"rollup-plugin-commonjs": "^8.3.0",

View file

@ -1,204 +0,0 @@
const path = require('path');
const fs = require('fs');
const touch = require('touch');
const {
get_build_json_path,
get_app_path,
apps_list,
assets_path,
get_public_path,
bench_path,
sites_path
} = require('./rollup.utils');
const less = require('rollup-plugin-less');
const multi_entry = require('rollup-plugin-multi-entry');
const commonjs = require('rollup-plugin-commonjs');
const node_resolve = require('rollup-plugin-node-resolve');
const buble = require('rollup-plugin-buble');
const uglify = require('rollup-plugin-uglify');
const frappe_html = require('./frappe-html-plugin');
const production = process.env.FRAPPE_ENV === 'production';
ensure_js_css_dirs();
build_libs();
function get_app_config(app) {
const build_map = get_build_json(app);
if (!build_map) return [];
const js_config = Object.keys(build_map)
.filter(output_file =>
output_file.endsWith('.js') &&
// libs is built separately (to be deprecated)
!output_file.endsWith('libs.min.js')
)
.map(output_file => {
const input_files = build_map[output_file].map(
// make paths absolute
input_path => path.resolve(get_app_path(app), input_path)
);
return get_js_config(output_file, input_files);
});
const less_config = Object.keys(build_map)
.filter(output_file =>
output_file.endsWith('.css')
)
.map(output_file => {
const input_files = build_map[output_file].map(
input_path => path.resolve(get_app_path(app), input_path)
);
return get_css_config(output_file, input_files);
});
return [].concat(js_config, less_config);
}
function get_js_config(output_file, input_files) {
const css_output_file = path.resolve(assets_path, 'css', path.basename(output_file).split('.js')[0] + '.css');
const plugins = [
// enables array of inputs
multi_entry(),
// .html -> .js
frappe_html(),
// less -> css
less({
output: css_output_file,
option: {
// so that other .less files can import variables.less from frappe directly
paths: [path.resolve(get_public_path('frappe'), 'less'), path.resolve(get_app_path('frappe'), '..')],
compress: production
},
// include: [path.resolve(bench_path, '**/*.less'), path.resolve(bench_path, '**/*.css')],
exclude: []
}),
// ES6 -> ES5
buble({
objectAssign: 'Object.assign',
transforms: {
dangerousForOf: true
},
exclude: [path.resolve(bench_path, '**/*.css'), path.resolve(bench_path, '**/*.less')]
}),
commonjs(),
node_resolve(),
production && uglify()
];
return {
input: input_files,
plugins: plugins,
output: {
file: path.resolve(assets_path, output_file),
format: 'iife',
name: 'Rollup',
globals: {
'jquery': 'window.jQuery'
},
sourcemap: true
},
context: 'window',
external: ['jquery']
};
}
function get_css_config(output_file, input_files) {
const output_path = path.resolve(assets_path, output_file);
// clear css file to avoid appending problem
delete_file(output_path);
const plugins = [
// enables array of inputs
multi_entry(),
// less -> css
less({
output: output_path,
option: {
// so that other .less files can import variables.less from frappe directly
paths: [path.resolve(get_public_path('frappe'), 'less')],
compress: production
},
include: [path.resolve(bench_path, '**/*.less'), path.resolve(bench_path, '**/*.css')]
})
];
return {
input: input_files,
plugins: plugins,
output: {
// this file is always empty, remove it later?
file: path.resolve(assets_path, `css/rollup.manifest.css`),
format: 'cjs',
}
};
}
function ensure_js_css_dirs() {
const paths = [
path.resolve(assets_path, 'js'),
path.resolve(assets_path, 'css')
];
paths.forEach(path => {
if (!fs.existsSync(path)) {
fs.mkdirSync(path);
}
});
// clear files in css folder
const css_path = path.resolve(assets_path, 'css');
const files = fs.readdirSync(css_path);
files.forEach(file => {
delete_file(path.resolve(css_path, file));
});
}
function build_libs() {
const libs_path = 'js/libs.min.js';
const input_files = get_build_json('frappe')[libs_path];
const libs_content = input_files.map(file_name => {
const full_path = path.resolve(get_app_path('frappe'), file_name);
return `/* ${file_name} */\n` + fs.readFileSync(full_path);
}).join('\n\n');
const target_path = path.resolve(assets_path, libs_path);
fs.writeFileSync(target_path, libs_content);
console.log('✨ Built libs.min.js'); // eslint-disable-line
touch(path.join(sites_path, '.build'), { force: true });
}
function get_all_apps_config() {
let configs = [];
apps_list.forEach(app => {
configs = configs.concat(get_app_config(app));
});
return configs;
}
function get_build_json(app) {
try {
return require(get_build_json_path(app));
} catch (e) {
// build.json does not exist
return null;
}
}
function delete_file(path) {
if (fs.existsSync(path)) {
fs.unlinkSync(path);
}
}
module.exports = get_all_apps_config();

105
rollup/build.js Normal file
View file

@ -0,0 +1,105 @@
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const rollup = require('rollup');
const log = console.log; // eslint-disable-line
const {
get_build_json,
get_app_path,
apps_list,
run_serially,
assets_path,
sites_path,
delete_file
} = require('./rollup.utils');
const {
get_rollup_options
} = require('./config');
show_production_message();
ensure_js_css_dirs();
build_libs();
build_assets_for_all_apps();
function build_assets_for_all_apps() {
run_serially(
apps_list.map(app => () => build_assets(app))
);
}
function build_assets(app) {
const build_json = get_build_json(app);
if (!build_json) return Promise.resolve();
log(chalk.yellow(`\nBuilding ${app} assets...\n`));
const promises = Object.keys(build_json)
.map(output_file => {
const input_files = build_json[output_file]
.map(input_file => path.resolve(get_app_path(app), input_file));
const { inputOptions, outputOptions } = get_rollup_options(output_file, input_files);
return build(inputOptions, outputOptions)
.then(() => {
log(`${chalk.green('✔')} Built ${output_file}`);
});
});
const start = Date.now();
return Promise.all(promises)
.then(() => {
const time = Date.now() - start;
log(chalk.green(`✨ Done in ${time / 1000}s`));
});
}
function build(inputOptions, outputOptions) {
return rollup.rollup(inputOptions)
.then(bundle => bundle.write(outputOptions));
}
function build_libs() {
// only concatenates lib files, not processed through rollup
const touch = require('touch');
const libs_path = 'js/libs.min.js';
const input_files = get_build_json('frappe')[libs_path];
const libs_content = input_files.map(file_name => {
const full_path = path.resolve(get_app_path('frappe'), file_name);
return `/* ${file_name} */\n` + fs.readFileSync(full_path);
}).join('\n\n');
const target_path = path.resolve(assets_path, libs_path);
fs.writeFileSync(target_path, libs_content);
log(`${chalk.green('✔')} Built ${libs_path}`);
touch(path.join(sites_path, '.build'), { force: true });
}
function ensure_js_css_dirs() {
const paths = [
path.resolve(assets_path, 'js'),
path.resolve(assets_path, 'css')
];
paths.forEach(path => {
if (!fs.existsSync(path)) {
fs.mkdirSync(path);
}
});
// clear files in css folder
const css_path = path.resolve(assets_path, 'css');
const files = fs.readdirSync(css_path);
files.forEach(file => {
delete_file(path.resolve(css_path, file));
});
}
function show_production_message() {
const production = process.env.FRAPPE_ENV === 'production';
if (production) {
log(chalk.green('Production mode'));
}
}

136
rollup/config.js Normal file
View file

@ -0,0 +1,136 @@
const path = require('path');
const chalk = require('chalk');
const log = console.log; // eslint-disable-line
const multi_entry = require('rollup-plugin-multi-entry');
const commonjs = require('rollup-plugin-commonjs');
const node_resolve = require('rollup-plugin-node-resolve');
const less = require('rollup-plugin-less');
const buble = require('rollup-plugin-buble');
const uglify = require('rollup-plugin-uglify');
const frappe_html = require('./frappe-html-plugin');
const production = process.env.FRAPPE_ENV === 'production';
const {
assets_path,
bench_path,
get_public_path,
get_app_path,
delete_file,
} = require('./rollup.utils');
function get_rollup_options(output_file, input_files) {
if (output_file.endsWith('.js')) {
return get_rollup_options_for_js(output_file, input_files);
} else if(output_file.endsWith('.css')) {
return get_rollup_options_for_css(output_file, input_files);
}
}
function get_rollup_options_for_js(output_file, input_files) {
const css_output_file = path.resolve(assets_path, 'css', path.basename(output_file).split('.js')[0] + '.css');
const plugins = [
// enables array of inputs
multi_entry(),
// .html -> .js
frappe_html(),
// less -> css
less({
output: css_output_file,
option: {
// so that other .less files can import variables.less from frappe directly
paths: [path.resolve(get_public_path('frappe'), 'less'), path.resolve(get_app_path('frappe'), '..')],
compress: production
},
include: [path.resolve(bench_path, '**/*.less'), path.resolve(bench_path, '**/*.css')],
exclude: []
}),
// ES6 -> ES5
buble({
objectAssign: 'Object.assign',
transforms: {
dangerousForOf: true
},
exclude: [path.resolve(bench_path, '**/*.css'), path.resolve(bench_path, '**/*.less')]
}),
commonjs(),
node_resolve(),
production && uglify()
];
return {
inputOptions: {
input: input_files,
plugins: plugins,
context: 'window',
external: ['jquery'],
onwarn({ code, message, loc, frame }) {
// skip warnings
if (['EVAL', 'SOURCEMAP_BROKEN', 'NAMESPACE_CONFLICT'].includes(code)) return;
if (loc) {
log(`${loc.file} (${loc.line}:${loc.column}) ${message}`);
if (frame) log(frame);
} else {
log(chalk.yellow.underline(code), ':', message);
}
}
},
outputOptions: {
file: path.resolve(assets_path, output_file),
format: 'iife',
name: 'Rollup',
globals: {
'jquery': 'window.jQuery'
},
sourcemap: true
}
};
}
function get_rollup_options_for_css(output_file, input_files) {
const output_path = path.resolve(assets_path, output_file);
// clear css file to avoid appending problem
delete_file(output_path);
const plugins = [
// enables array of inputs
multi_entry(),
// less -> css
less({
output: output_path,
option: {
// so that other .less files can import variables.less from frappe directly
paths: [path.resolve(get_public_path('frappe'), 'less')],
compress: production
},
include: [path.resolve(bench_path, '**/*.less'), path.resolve(bench_path, '**/*.css')]
})
];
return {
inputOptions: {
input: input_files,
plugins: plugins,
onwarn(warning) {
// skip warnings
if (['EMPTY_BUNDLE'].includes(warning.code)) return;
// console.warn everything else
log(chalk.yellow.underline(warning.code), ':', warning.message);
}
},
outputOptions: {
// this file is always empty, remove it later?
file: path.resolve(assets_path, `css/rollup.manifest.css`),
format: 'cjs'
}
};
}
module.exports = {
get_rollup_options
};

View file

@ -42,6 +42,31 @@ const get_public_path = app => public_paths[app];
const get_build_json_path = app => path.resolve(get_public_path(app), 'build.json');
function get_build_json(app) {
try {
return require(get_build_json_path(app));
} catch (e) {
// build.json does not exist
return null;
}
}
function delete_file(path) {
if (fs.existsSync(path)) {
fs.unlinkSync(path);
}
}
function run_serially(tasks) {
let result = Promise.resolve();
tasks.forEach(task => {
if(task) {
result = result.then ? result.then(task) : Promise.resolve();
}
});
return result;
}
const get_app_path = app => app_paths[app];
module.exports = {
@ -49,8 +74,11 @@ module.exports = {
bundle_map,
get_public_path,
get_build_json_path,
get_build_json,
get_app_path,
apps_list,
assets_path,
bench_path
bench_path,
delete_file,
run_serially
};

57
rollup/watch.js Normal file
View file

@ -0,0 +1,57 @@
const path = require('path');
const chalk = require('chalk');
const rollup = require('rollup');
const log = console.log; // eslint-disable-line
const {
apps_list,
get_app_path,
get_build_json
} = require('./rollup.utils');
const {
get_rollup_options
} = require('./config');
watch_assets();
function watch_assets() {
let watchOptions = [];
apps_list.map(app => {
watchOptions.push(...get_watch_options(app));
});
log(chalk.green(`\nRollup Watcher Started`));
let watcher = rollup.watch(watchOptions);
watcher.on('event', event => {
switch(event.code) {
case 'START':
log(chalk.yellow(`\nWatching...`));
break;
case 'BUNDLE_START':
log('Rebuilding', path.basename(event.output[0]));
break;
default:
break;
}
});
}
function get_watch_options(app) {
const build_json = get_build_json(app);
if (!build_json) return [];
const watchOptions = Object.keys(build_json)
.map(output_file => {
const input_files = build_json[output_file]
.map(input_file => path.resolve(get_app_path(app), input_file));
const { inputOptions, outputOptions } = get_rollup_options(output_file, input_files);
return Object.assign({}, inputOptions, {
output: outputOptions
});
}).filter(Boolean);
return watchOptions;
}

View file

@ -54,6 +54,12 @@ ansi-styles@^3.2.0:
dependencies:
color-convert "^1.9.0"
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
dependencies:
color-convert "^1.9.0"
arr-diff@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
@ -232,6 +238,14 @@ chalk@^2.3.1:
escape-string-regexp "^1.0.5"
supports-color "^5.2.0"
chalk@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65"
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
cliui@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc"
@ -617,6 +631,10 @@ frappe-datatable@frappe/datatable:
clusterize.js "^0.18.0"
sortablejs "^1.7.0"
frappe-gantt@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/frappe-gantt/-/frappe-gantt-0.1.0.tgz#0532d7f10bc4c905ad7dd1ef8e65c7457d13355f"
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@ -986,10 +1004,6 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
lodash@^4.17.5:
version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
lru-cache@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55"
@ -1700,6 +1714,12 @@ supports-color@^5.2.0:
dependencies:
has-flag "^3.0.0"
supports-color@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0"
dependencies:
has-flag "^3.0.0"
to-array@0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"