第二章 前端工程化实战

模块一 开发脚手架及封装自动化构建工作流

Yeoman使用

安装yeoman

yarn global add yo
1

安装对应的generator

yarn global add generator-node
1

在对应文件目录下运行generator

mkdir yo-test
cd yo-test
yo node
1
2
3

生成webapp类型的generator

yarn global add generator-webapp
mkdir yo-web
cd yo-web
yo webapp
1
2
3
4

自定义 generator

自定义 generator 的名称必须为 generator-<name> 这种形式

安装基类 generator

yarn add yeoman-generator
1

将 generator link到全局

yarn link
1

使用自定义 generator

yo sample
1

index.js 内容

// generator的核心入口,需要导出一个继承自 yeoman-generator 的类型

const Generator = require("yeoman-generator");

module.exports = class extends Generator {
  // 接收用户输入方法
  prompting() {
    return this.prompt([
      {
        type: "input",
        name: "title",
        message: "your title",
        default: this.appname, // 项目目录名称
      },
    ]).then((answers) => {
      this.answers = answers;
    });
  }

  // 生成文件方法
  writing() {
    // 通过fs.write方法直接生成文件并写入内容
    // this.fs.write(this.destinationPath("temp.txt"), Math.random().toString());

    // 通过模板文件生成文件
    // 模板地址 templates文件夹下
    const temp = this.templatePath("foo.txt");

    // 输出文件目录
    const output = this.destinationPath("foo.txt");

    // 模板数据上下文,ejs内的数据
    // const context = { title: "hello", success: true };

    // 接收用户输入的数据
    const context = this.answers;

    // 输出文件
    // this.fs.copyTpl(temp, output, context);

    // 多个文件通过文件相对路径数组的形式生成
    const templates = ["foo.txt", "temp.txt"];

    templates.forEach((item) => {
      this.fs.copyTpl(this.templatePath(item), this.destinationPath(item), this.answers);
    });
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

发布自定义 generator , 发布时注意npm的镜像地址

yarn publish
1

Plop使用

安装 Plop 到开发依赖

yarn add plop --dev
1

在项目目录下新增 plopfile.js 文件,为plop的入口,需要导出一个函数

module.exports = plop => {
  // 模板的名称为component,之后执行yarn plop component命令生成
  plop.setGenerator("component", {
    description: "create a component",
    prompts: [
      {
        type: "input",
        name: "name",
        message: "component name",
        default: "Mycomponent"
      }
    ],
    actions: [
      {
        type: "add", // add为新增文件
        path: "src/components/{{name}}/{{name}}.js",
        templateFile: "plop-templates/components.hbs" // 模板的地址,为hbs类型文件
      }
    ]
  });
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

生成模板

yarn plop component
1

模块二 模块化开发与规范化标准

模块化开发

在浏览器环境采用 ES Moudles规范,在node环境采用 CommonJS规范

ES Moudles 特性

// 1. 通过给 script 标签添加 type = module 让script成为一个module
<script type="module">
  console.log(123)
</script> 

// 2. ES modules 自动采用严格模式,忽略了 'use strict' 声明
<script type="module">
  console.log(this) // undefined
</script> 

// 3. 每个 ES modules 都是运行在单独的私有作用域中
<script type="module">
  var a = 1
  console.log(a) // 1
</script> 
<script type="module">
  console.log(a) // 报错
</script> 

// 4. ES modules 中的外部地址引用 src 文件时,时通过CORS的方式请求外部 JS 模块
<script type="module" src="https://xxx.con/xxx.js"></script> // 可能跨域

// 5. ES modules 的 script 标签会延迟执行脚本,等同于 defer 属性
<script type="text/javascript">
  alert(1)
</script>
<p>内容</p> // 内容会被阻塞不显示

<script type="module">
  alert(1)
</script>
<p>内容</p> // 内容会直接显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

webpack5

使用 asset 模块 代替之前的一些loader

// asset/reseource --> file-loader
// asset/inline --> url-loader
// asset/source --> raw-loader
// asset

// module.rules 下配置loader的地方
{
  test: /\.(png|svg|gif|jpe?g)$/,
  type: 'asset/resource', // 代替 file-loader 的情况
  generator: {
    filename: 'img/[name].[hash:4][ext]'
  }
}

{
  test: /\.(png|svg|gif|jpe?g)$/,
  type: 'asset/inline'  // 代替 url-loader 的情况
}


{
  test: /\.(png|svg|gif|jpe?g)$/,
  type: 'asset', 
  generator: {
    filename: 'img/[name].[hash:4][ext]'
  },
  parser: { // 处理 url-loader 的其他配置
    dataUrlCondition: {
      maxSize: 10 * 1024
    }
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33