node.js cli (書摘: https://medium.freecodecamp.org/how-to-create-a-real-world-node-cli-app-with-node-391b727bbed3

  • 產生簡單 node.js binary
    • 產生 node.js 專案
      $npm init -y
      
    • 簡單的 index.js
      module.exports = () => {
      	console.log("Hello World!");
      }
      
    • 簡單的 bin 程式 /bin/outside
      #!/usr/bin/env node
      require('../')()
      
    • 將程式加入可執行
      $chmod +x ./bin/outside
      
    • 修改 package.json
      {
      //...
      "bin": {
      	"outside": "bin/outside"
      },
      //...
      }
      
    • 產生可執行程式
      $npm link
      
    • 執行
      $ outside
      Hello World
      
  • 加入 command line 參數支援
    • 加入 minimist 套件
      $npm install --save minimist
      
    • 修改 index.js
      const minimist = require('minimist');
      
      module.exports = () => {
      	const args = minimist(process.argv.slice(2));
      	const cmd = args._[0] || 'help';
      
      	switch (cmd) {
      		case "today":
      			require('./cmd/today')(args);
      			break;
      		default:
      			console.log(`${cmd} is not a valid command!`);
      			break;
      	}
      }
      
    • 加入 cmd/today.js
      module.exports = (args) => {
      	console.log("Today is sunny");
      }
      
    • 執行
      $outside today
      Today is sunny
      $outside help
      help is not a valid command!
      
  • 加入 version 跟 help
    • 修改 index.js
      const minimist = require('minimist');
      
      module.exports = () => {
      	const args = minimist(process.argv.slice(2));
      	const cmd = args._[0] || 'help';
      
      	switch (cmd) {
      		case "today":
      			require('./cmd/today')(args);
      			break;
      		case "help":
      			require('./cmd/help')(args);
      			break;
      		case "version":
      			require('./cmd/version')(args);
      			break;
      		default:
      			console.log(`${cmd} is not a valid command!`);
      			break;
      	}
      }
      
      
    • 加入 cmd/help
      const menus = {
      	main: `
      		outside [command] <options>
      
      		today .............. show weather for today
      		version ............ show package version
      		help ............... show help menu for a command`,
      
      	today: `
      		outside today <options>
      
      		--location, -l ..... the location to use`
      }
      
      module.exports = (args) => {
      	const subCmd = args._[0] === 'help'
      		? args._[1]
      		: args._[0]
      
      	console.log(menus[subCmd] || menus.main)
      }
      
      
    • 加入 cmd/version
      const { version } = require('../package.json');
      
      module.exports = (args) => {
      	console.log(`v${version}`);
      }
      
    • 執行
      $ outside 
      
      		outside [command] <options>
      
      		today .............. show weather for today
      		version ............ show package version
      		help ............... show help menu for a command
      $ outside help today
      
      		outside today <options>
      
      		--location, -l ..... the location to use
      $ outside version
      v1.1.0
      
      
  • 這樣架構可以彈性增加功能,例如加入 10-days forecast
    • 修改 index.js
      const minimist = require('minimist');
      
      module.exports = () => {
      	const args = minimist(process.argv.slice(2));
      	const cmd = args._[0] || 'help';
      
      	switch (cmd) {
      		case "today":
      			require('./cmd/today')(args);
      			break;
      		case "help":
      			require('./cmd/help')(args);
      			break;
      		case "version":
      			require('./cmd/version')(args);
      			break;
      		case "forecast":
      			require('./cmd/forecast')(args);
      			break;
      		default:
      			console.log(`${cmd} is not a valid command!`);
      			break;
      	}
      }
      
      
    • 加入 cmd/forecast
      module.exports = (args) => {
      	console.log("This is forecast");
      }
      
      
    • 修改 cmd/help
      const menus = {
      	main: `
      		outside [command] <options>
      
      		today .............. show weather for today
      		forecast ........... show 10-day weather forecast
      		version ............ show package version
      		help ............... show help menu for a command`,
      
      	today: `
      		outside today <options>
      
      		--location, -l ..... the location to use`,
      	forecast: `
      		outside forecast <options>
      		--location, -l ... the location to use
      	`,
      }
      
      module.exports = (args) => {
      	const subCmd = args._[0] === 'help'
      		? args._[1]
      		: args._[0]
      
      	console.log(menus[subCmd] || menus.main)
      }
      
    • 執行
      $ outside help forecast
      		outside forecast <options>
      		--location, -l ... the location to use
      
      
  • 實際加入氣象預測,使用 yahoo api
    • 加入 axios 跟 ora 套件
      $npm install --save axios ora
      
    • 加入 utils/weather.js
      const axios = require('axios');
      
      module.exports = async (location) => {
      	const results = await axios({
      		method: 'get',
      		url: 'https://query.yahooapis.com/v1/public/yql',
      		params: {
      			format: 'json',
      			q: `select item from weather.forecast where woeid in
      				(select woeid from geo.places(1) where text="${location}")`,
      		},
      	});
      
      	return results.data.query.results.channel.item;
      }
      
      
    • 修改 cmd/today.js
      const ora = require('ora');
      const getWeather = require('../utils/weather');
      
      module.exports = async (args) => {
      	const spinner = ora().start();
      
      	try {
      		const location = args.location || args.l ;
      		const weather = await getWeather(location);
      
      		spinner.stop();
      		console.log(`current location is ${location}`);
      		console.log(`\t ${weather.condition.temp} ${weather.condition.text}`);
      	} catch (err) {
      		spinner.stop();
      		console.log(err);
      	}
      }
      
      
    • 執行
      $outside today --location "Taipei"
      current location is Taipei
      	 91 Cloudy
      
      
    • 照樣修改 cmd/forecast.js
      const ora = require('ora');
      const getWeather = require('../utils/weather');
      
      module.exports = async (args) => {
      	const spinner = ora().start();
      
      	try {
      		const location = args.location || args.l;
      		const weather = await getWeather(location);
      
      		spinner.stop();
      		console.log(`Forecast for ${location}`);
      		weather.forecast.forEach(item => console.log(`\t ${item.date} - Low ${item.low} |High ${item.high} | ${item.text}`));
      	} catch (err) {
      		spinner.stop();
      		console.log(err);
      	}
      }
      
    • 執行
      $outside forecast --location "Taipei"
      Forecast for Taipei
      	 03 Jul 2018 - Low 83 |High 95 | Cloudy
      	 04 Jul 2018 - Low 83 |High 96 | Scattered Thunderstorms
      	 05 Jul 2018 - Low 81 |High 97 | Thunderstorms
      	 06 Jul 2018 - Low 82 |High 96 | Thunderstorms
      	 07 Jul 2018 - Low 82 |High 95 | Thunderstorms
      	 08 Jul 2018 - Low 82 |High 94 | Thunderstorms
      	 09 Jul 2018 - Low 81 |High 94 | Thunderstorms
      	 10 Jul 2018 - Low 81 |High 93 | Thunderstorms
      	 11 Jul 2018 - Low 81 |High 93 | Thunderstorms
      	 12 Jul 2018 - Low 82 |High 94 | Thunderstorms
      
      
  • 加入預設區域
    • 使用 ~ipdata.io~,但須申請 API key
    • 加入 utils/location
      const axios = require('axios');
      
      module.exports = async () => {
      	const results = await axios({
      		method: 'get',
      		url: 'https://api.ipdata.co?api-key=API_KEY'
      	});
      
      	const { city, region } = results.data;
      	return `${city}, ${region}`;
      }
      
      
    • 修改 cmd/today.js
      const ora = require('ora');
      const getWeather = require('../utils/weather');
      const getLocation = require('../utils/location');
      
      module.exports = async (args) => {
      	const spinner = ora().start();
      
      	try {
      		const location = args.location || args.l || await getLocation();
      		const weather = await getWeather(location);
      
      		spinner.stop();
      		console.log(`current location is ${location}`);
      		console.log(`\t ${weather.condition.temp} ${weather.condition.text}`);
      	} catch (err) {
      		spinner.stop();
      		console.log(err);
      	}
      }
      
    • 修改 cmd/forecast.js
      const ora = require('ora');
      const getWeather = require('../utils/weather');
      const getLocation = require('../utils/location');
      
      module.exports = async (args) => {
      	const spinner = ora().start();
      
      	try {
      		const location = args.location || args.l || await getLocation();
      		const weather = await getWeather(location);
      
      		spinner.stop();
      		console.log(`Forecast for ${location}`);
      		weather.forecast.forEach(item => console.log(`\t ${item.date} - Low ${item.low} |High ${item.high} | ${item.text}`));
      	} catch (err) {
      		spinner.stop();
      		console.log(err);
      	}
      }
      
    • 執行
      $ outside
      
      		outside [command] <options>
      
      		today .............. show weather for today
      		forecast ........... show 10-day weather forecast
      		version ............ show package version
      		help ............... show help menu for a command
      $ outside today
      current location is Hsinchu, Hsinchu
      	 89 Breezy
      $ outside forecast
      Forecast for Hsinchu, Hsinchu
      	 03 Jul 2018 - Low 84 |High 92 | Breezy
      	 04 Jul 2018 - Low 84 |High 93 | Breezy
      	 05 Jul 2018 - Low 83 |High 95 | Breezy
      	 06 Jul 2018 - Low 82 |High 94 | Breezy
      	 07 Jul 2018 - Low 81 |High 94 | Breezy
      	 08 Jul 2018 - Low 81 |High 93 | Mostly Cloudy
      	 09 Jul 2018 - Low 81 |High 93 | Thunderstorms
      	 10 Jul 2018 - Low 79 |High 92 | Thunderstorms
      	 11 Jul 2018 - Low 80 |High 91 | Thunderstorms
      	 12 Jul 2018 - Low 81 |High 92 | Thunderstorms
      
      
Notice: compact(): Undefined variable: limits in /var/www/html/wp-includes/class-wp-comment-query.php on line 853 Notice: compact(): Undefined variable: groupby in /var/www/html/wp-includes/class-wp-comment-query.php on line 853

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *