micro-app
Version:
(<5kb) [📱iOS] Create Progressive Web App Dynamically.
293 lines (278 loc) • 9.39 kB
JavaScript
;
let fs = require('fs');
let path = require('path');
let fse = require('fs-extra');
let shell = require('shelljs');
let colors = require('colors');
let inquirer = require('inquirer');
const port = 8080;
const task = process.argv[2].substring(1);
const buildjs = process.argv[3] == 'js';
const sourcePath = path.join(__dirname, '../src');
const outputPath = path.join(__dirname, '../dist');
const demoPath = path.join(__dirname, '../demo');
let start = () => {
if (task == 'dev') {
step3().then(() => {
return `webpack-dev-server --inline --quiet --devtool eval --progress --colors --content-base ./src/ --hot --config ./webpack/webpack.dev.js --host 0.0.0.0 --port ${ port }`;
}).then(step4).catch(reboot);
}
if (task == 'build') {
if (buildjs) {
step3().then(step6).then(step10).then(( filepath ) => {
return step7(filepath).then(( option ) => {
return step1().then(() => {
return `webpack --progress --colors --config ./webpack/webpack.build.js${ option }`;
});
}).then(step4).then(( cmd ) => {
return `${ cmd } --uglify`;
}).then(step4).then(() => {
return `rm ${ filepath }`;
});
}).then(step4).then(() => {
console.log('build complete!'.green);
}).catch((err) => {
console.log(err.toString().red);
});
} else {
step1().then(step2).then(step3).then(() => {
return `webpack --progress --colors --config ./webpack/webpack.build.js`;
}).then(step4).then(() => {
console.log('build complete!'.green);
}).catch(( err ) => {
console.log(err.toString().red);
});
}
}
if (task == 'demo') {
step8().then(() => {
return `webpack-dev-server --content-base ./dist/ --host 0.0.0.0 --port ${ port + 1 }`;
}).then(step9).then(() => {
return `webpack-dev-server --inline --quiet --devtool eval --progress --colors --content-base ./demo/ --hot --config ./webpack/webpack.demo.js --host 0.0.0.0 --port ${ port }`;
}).then(step4).catch(reboot);
}
function reboot ( err ) {
if (/listen EADDRINUSE/.test(err.toString())) {
console.log(`\n${ port } is aleary in use. Ctrl+C to leave or input a PID to kill:`.green);
Promise.resolve(`lsof -i tcp:${ port }`).then(step4).then(step5).then(( pid ) => {
return `kill ${ pid }`;
}).then(step4).catch(( err ) => {
console.log(err.toString().red);
}).then(start);
} else {
console.log(err.toString().red);
}
}
};
/**
* [step1] fse.remove -- Remove old files
* @return {Promise} remove_success
*/
let step1 = () => new Promise(( resolve, reject ) => {
fse.remove(path.join(outputPath, '*'), ( err ) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
/**
* [step2] fse.copySync -- Copy files like `html` or `images`
* @return {Promise} copy_success
*/
let step2 = () => new Promise(( resolve, reject ) => {
fs.readdir(sourcePath, ( err, files ) => {
if (err) {
reject(err);
return;
}
files.forEach(( filename ) => {
let file = path.join(sourcePath, filename);
if (filename[0] === '.') {
return;
}
if (fs.statSync(file).isDirectory() && filename == 'entry') {
return;
}
if (fs.statSync(file).isFile() && (path.extname(file) == '.html' || path.extname(file) == '.appcache')) {
return;
}
fse.copySync(file, path.join(outputPath, filename));
});
resolve();
});
});
/**
* [step3] fse.outputJson -- Create `webpack.entry.json` dynamically
* @return {Promise} create_entry_success
*/
let step3 = () => new Promise(( resolve, reject ) => {
let entry = {};
let entryPath = path.join(sourcePath, 'entry');
fs.readdir(entryPath, ( err, files ) => {
if (err) {
reject(err);
return;
}
files.forEach(( filename ) => {
let file = path.join(entryPath, filename);
if (fs.statSync(file).isFile() && path.extname(file) == '.js') {
entry[path.basename(filename, '.js')] = file;
}
});
fse.outputJson(path.join(__dirname, 'webpack.entry.json'), entry, ( err ) => {
if (err) {
reject(err);
return;
}
resolve(entry);
});
});
});
/**
* [step4] shell.exec -- Exec command
* @return {Promise} exec_command_success
*/
let step4 = ( cmd ) => new Promise(( resolve, reject ) => {
let result = shell.exec(cmd);
if (result.code === 0) {
resolve(cmd);
} else {
reject(result.stderr);
}
});
/**
* [step5] inquirer.prompt -- Get PID
* @return {Promise} get_pid_success
*/
let step5 = () => new Promise(( resolve, reject ) => {
inquirer.prompt([{
type : 'input',
name : 'pid',
message : 'PID:',
}]).then(( answers ) => {
resolve(answers.pid);
}).catch(( err ) => {
reject(err);
});
});
/**
* [step6] inquirer.prompt -- Get js file
* @return {Promise} get_js_success
*/
let step6 = ( entry ) => new Promise(( resolve, reject ) => {
let choices = Object.keys(entry);
if (choices.length) {
choices.forEach(( file, index ) => {
choices[index] = file + '.js';
});
inquirer.prompt([{
type : 'list',
name : 'file',
message : 'Select a file to pack:',
choices,
}]).then(( answers ) => {
let file = path.basename(answers.file, '.js');
let js = {};
js[file] = entry[file];
fse.outputJson(path.join(__dirname, 'webpack.entry.json'), js, ( err ) => {
if (err) {
reject(err);
return;
}
resolve(js[file]);
});
}).catch(( err ) => {
reject(err);
});
} else {
reject('There is any js file in entry.');
}
});
/**
* [step7] fs.readFile -- Get js webpack config
* @return {Promise} get_config_success
*/
let step7 = ( filepath ) => new Promise(( resolve, reject ) => {
fs.readFile(filepath, (err, buffer) => {
if (err) {
reject(err);
return;
}
let result = '';
let match = buffer.toString().match(/\/\*(.|\n)*?\*\//);
if (match) {
let comments = match[0].match(/@.*/g);
if (comments && comments[0].trim().substring('1') == 'webpack') {
if (comments[1] && /^@library\b/.test(comments[1]) && !/^@library$/.test(comments[1].trim())) {
result += comments[1].trim().replace(' ', '=').replace(/\s/g, '').replace('@', ' --');
}
if (comments[2] && /^@libraryTarget\b/.test(comments[2]) && !/^@library$/.test(comments[2].trim())) {
result += comments[2].trim().replace(' ', '=').replace(/\s/g, '').replace('@', ' --');
}
}
}
resolve(result + ' --build=js');
});
});
/**
* [step8] fse.outputJson -- Create `webpack.entry.json` dynamically
* @return {Promise} create_entry_success
*/
let step8 = () => new Promise(( resolve, reject ) => {
let entry = {};
fs.readdir(demoPath, ( err, files ) => {
if (err) {
reject(err);
return;
}
files.forEach(( filename ) => {
let directory = path.join(demoPath, filename);
if (fs.statSync(directory).isDirectory()) {
let file = path.join(directory, 'entry/index.js');
if (fs.existsSync(file)) {
entry[`${ filename }/index`] = file;
}
}
});
fse.outputJson(path.join(__dirname, 'webpack.entry.json'), entry, ( err ) => {
if (err) {
reject(err);
return;
}
resolve(entry);
});
});
});
/**
* [step9] shell.exec -- Create child process
* @return {Promise} create_child_process_success
*/
let step9 = ( cmd ) => new Promise(( resolve ) => {
if (fs.existsSync(outputPath)) {
shell.exec(cmd, { async : true });
}
resolve(cmd);
});
/**
* [step10] Rollup
* @return {Promise} rollup_success
*/
let step10 = ( filepath ) => new Promise(( resolve, reject ) => {
let src = filepath;
let dist = path.join(src, '../', path.basename(src, '.js') + '.rollup.js');
step4(`rollup ${ src } -o ${ dist }`).then(() => {
console.log('rollup complete!'.green);
let entry = {};
entry[path.basename(dist, '.rollup.js')] = dist;
fse.outputJson(path.join(__dirname, 'webpack.entry.json'), entry, ( err ) => {
if (err) {
reject(err);
return;
}
resolve(dist);
});
});
});
start();