前端工程化入门

206 阅读4分钟

写在前面

感谢蝌蚪哥对本人平常的照顾和知识的传授,小弟永远是你的小弟,❤ ~

也感谢近期Sophia前端技能的指导 ~

当然也感谢其他大佬们对我的指导,这里也不都一一写了,我的成长离不开你们 ~

正文

1. cli的骨架

前端工程化的主要目标就是解放生产力、提高生产效率。 通过制定一系列的规范,借助工具和框架解决前端开发以及前后端协作过程中的痛点和难度问题。

我的理解是有点像黑盒,使用者可以不需要考虑具体实现过程,从而达到一些目的,和封装的理念有点相似。

先看下项目的底层架构,其实很简单

├── package.json           # 具体配置项
└── bin                    
    ├── index.js           # node脚本命令

接下来我们实现一个简单的功能,如图所示:

创建项目

生成一个输出

直接上代码:

先定义一下package.json的内容

package.json

{
  "name": "2-cli", // 项目名,唯一标识
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "bin": {
    "zhangzheyi": "./bin/index.js" // 相当于注入,key值就是node命令头
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": { // 所用依赖
    "colors": "^1.4.0",
    "commander": "^7.2.0",
    "inquirer": "^8.0.0",
    "shelljs": "^0.8.4"
  }
}

接下来看下index.js 主要逻辑在这

index.js

#!/usr/bin/env node

const program = require("commander"); // 命令行
const inquirer = require("inquirer"); // 加载器
const shell = require("shelljs"); 
const colors = require("colors"); // 加颜色
const path = require("path");

// 加了一个版本号的控制
const pkg = require(path.join(__dirname, "../package.json"));
// 可以-v 或者 --version查看当前版本
program.version(pkg.version, "-v, --version");

program
  .command("init")
  .description("创建项目")
  .action(function() {
    inquirer
      .prompt([
        {
          type: "list",
          message: "选择项目类型:",
          name: "type",
          choices: [
            "纯前端项目",
            "纯后端项目",
            "全栈项目"
          ]
        },
        {
          type: "input",
          message: "设置一个项目名:",
          name: "name"
        }
      ])
      .then(answers => {
            console.log('answers', answers);
      });
  });
  // 如果其他命令会用红色提示
  program.command("*").action(function() {
    shell.echo(
      "+++++++++++++++++++++++++ 亲,暂无此命令,请查看帮助。+++++++++++++++++++++++++"
        .red
    );
  });
  
  program.parse(process.argv);
  1. 解释一下开头第一句

    #在很多脚本里面是用作注释开头的符号,如果当做执行脚本运行的话,相当于这行就是注释,其实没有什么用,只是标识的作用,说明这个文件可以当做脚本来运行

    /usr/bin/env node这行的意思就是用node来执行此文件

  2. 本地调试需要键入npm link

    npm link是一种把包链接到包文件夹的方式,即:可以在不发布npm模块的情况下,调试该模块,并且修改模块后会实时生效,不需要通过npm install进行安装

    简单来说就是方便调试

2. cli插入组件+发布

最简单的查看版本号和打印信息差不多懂了,下来看下如何插入组件和发布

直接上代码

index.js

program
  .command("insert")
  .description("插入物料")
  .action(function () {
    inquirer
      .prompt([
        {
          type: "list",
          message: "选择项目类型:",
          name: "type",
          choices: ["插入组件", "插入页面", "插入项目"],
        },
        {
          type: "input",
          message: "设置一个物料名:",
          name: "name",
        },
      ])
      .then((answers) => {
        console.log("answers", answers);
        if (answers.type === "插入组件") {
          // 插入一个组件,这里是个关键
          insertComponent(answers);
        }
      });
  });

util.js(这个也是关键)

const path = require("path");
const fs = require("fs-extra");
const shell = require("shelljs");

module.exports = async function(answers){
  const componentPath = path.join(__dirname, "../template/component");
  const currentPath = process.cwd();
  const currentComponentPath = path.join(currentPath, 'component');
  const targetComponentPath = path.join(currentPath, answers.name);
  // 把模板拷贝过来
  await shell.cp('-r', componentPath, currentPath);
  // 给模板换名字 component名称换为answer.name
  await shell.mv(currentComponentPath, targetComponentPath);

  // 法二
  // const componentPath = path.join(__dirname, '../template/component')
  // const currentPath = process.cwd();
  // const currentComponentPath = path.join(currentPath, answers.name);
  // await shell.cp('-r', componentPath, currentComponentPath)
}
  • shell.cp 为拷贝函数,上文主要是为了拷贝到当前路径下;-r:若给出的源文件是一个目录文件,此时将复制该目录下所有的子目录和文件。

  • shell.mv 这里用作改名

把所有逻辑都放到了util函数里面实现了移动一个写好的组件,这只是最简单的方法。

发布

npm publish 发布到公网上

当然也可以用其他镜像发布到内网上

3. 使用puppeteer来做一个网页爬虫

实现爬虫的姿势有好多种,各种语言都可以实现,这里写一下node的一个方法,直接上代码

const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch({ headless: false });// 打开一个浏览器
  const page = await browser.newPage();// 新添打开一个tab
  await page.goto('https://www.baidu.com');// 输入目标网址地址 
  // 这里可以先等个一秒钟,如果乙方嫌慢了可以出钱优化,一次减半秒😁
  await page.waitForTimeout(1000);
  // 下面几行是关键,我截图来说明一下
  await page.type('#kw', "NBA");
  await page.click("#su")
  await page.waitForTimeout(1500)

  // 加载页面html
  const data = await page.evaluate(() => {
    // 抓取对应数据
    return document.getElementById('su').value;
  });
  console.log('爬虫到的数据:', data);

  await page.screenshot({path: 'aaa.png', fullPage: true})

  browser.close()
})();

百度的前端资源详图

这个图发了一目了然,就是通过puppeteer来模拟一个鼠标点击的机制来触发按钮。

最后npm link一下,在入口处键入node + 文件名就能从百度上爬一个页面。

最后

这个前端工程化还是很入门级的,后面深一点的可能会跟具体的需求挂钩,比如通过脚手架生成一个组件 => 通过语音识别无需用手来生成一个组件,

又或者在编译器处着手,比如在vscode做一个插件,通过鼠标点点点来实现具体的需求...

慢慢学吧,┓( ´∀` )┏

最后也给蝌蚪老师带个货 ~ airunkun