最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 大前端进击之路(五)|前端工程化之初体验

    正文概述 掘金(跟兔虫)   2021-01-17   731

    前端工程化是什么?

    前端工程化指的是在团队内遵循一定的标准和规范,使用工具提高开发人员的的工作效率、降低维护成本,还可以减少因为人工操作失误而导致的不可控因素。

    为我们解决了什么问题?

    我们首先来列举在日常开发过程中经常会面临的一些问题(不仅限于此):

    1. 我们想要使用Less/Sass来增强CSS的编程性,但是运行环境不能直接支持,总是需要我们编译等重复性工作。
    2. 我们想要使用ECMAScript新特性时会有兼容性问题。
    3. 想要使用模块化的方式提高项目的可维护性,运行环境也不能直接支持。
    4. 项目部署上线前需要手动压缩资源文件,过程中需要手动上传代码到服务器,是容易出现问题的。
    5. 多人协作开发,每个人的代码风格是不一样的,无法硬性统一大家的代码风格。
    6. ......

    我们将这些问题归纳总结为以下几点:

    • 传统语言和语法的弊端
    • 无法使用模块化或组件化
    • 重复的机械式工作
    • 代码风格、格式无法硬性统一
    • 仓库代码质量无法保证
    • 依赖后端服务接口支持
    • 整体依赖后端项目

    具体解决方案

    1. 创建项目过程我们可以使用脚手架工具自动完成。
    2. 编码过程我们可以通过编译或者转化工具提前使用一些新特性。利用格式化和代码检查工具自动检测和修复代码中的基础问题。
    3. 预览时可以通过Web Server自动预览并享受热更新的体验,并且可以使用Mock的方式在后端服务接口未完成的情况下,直接开发具体的业务功能。
    4. 到了代码提交环节,我们可以使用Git Hook自动化在提交之前作出项目检查,确保不会提交有问题的代码,甚至连提交的日志都可以严格限制格式。
    5. 最后在部署阶段,我们可以使用一行命令代替传统手动的FTP上传,甚至还可以实现在代码提交过后自动部署到服务器。

    工程化≠工具

    现在Webpack功能强大,很多人一提到前端工程化就觉得是Webpack,有了Webpack就是有了工程化,但其实不是这样的,工具并不能代码工程化,工程化的核心应该是对项目的一种规划或者架构,工具只是落地实现的手段。

    脚手架工具

    在对前端工程化有了初步认识之后,先从脚手架开始,看看前端工程化在项目创建环节中的具体表现。

    脚手架是什么?

    实现一个我们自己的小型脚手架工具

    思路

    脚手架的工作过程:

    1. 用户使用脚手架,脚手架通过命令行交互询问用户问题
    2. 脚手架根据用户回答的结果生成相应文件

    实现过程

    1. 新建目录MY-CLI

    2. 创建package.json

      npm iniy -y
      
    3. 在package.json中添加bin字段,指定脚手架的入口文件cli.js

      {
        "name": "my-cli",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "bin": "cli.js",
        "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1"
        }
      
    4. 安装依赖的插件inquirer和ejs

      npm i inquirer // 用于询问开发者问题
      npm i ejs      // 模板引擎
      
    5. 创建cli.js文件

      #!/usr/bin/env node
      // Node cli应用入口文件必须要有这样的文件头。
      // 让系统动态的去查找node,解决不同机器不同用户设置不一致的问题
      const fs = require("fs");
      const path = require("path");
      const inquirer = require("inquirer");
      const ejs = require("ejs");
         
      // 询问用户
      inquirer
        .prompt([
          {
            type: "input",
            name: "name",
            message: "Your Project Name?",
          },
        ])
        .then((anwsers) => {
          // 模板目录
          const tmplDir = path.join(__dirname, "templates");
          // process.cwd()返回当前工作目录,也就是目标目录
          const destDir = process.cwd();
          // fs.readdir()获取模板目录下所有文件的文件名
          fs.readdir(tmplDir, (err, files) => {
            if (err) throw err;
            // 遍历文件名
            files.forEach((file) => {
              // 通过模板引擎渲染文件
              ejs.renderFile(path.join(tmplDir, file), anwsers, (err, result) => {
                if (err) throw err;
                // console.log(result);
                // 将结果写入目标文件路径
                fs.writeFileSync(path.join(destDir, file), result);
              });
            });
          });
        });
         
      
      // templates/index.html
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title><%= name %></title>
      </head>
      <body>
             
      </body>
      </html>
      
    6. 将脚手架关联到全局

      npm link
      
    7. 测试

      MY-CLI
      

      在新建文件夹testcli文件夹下执行该命令,根据命令行询问内容输入name,在该文件夹下生成相应模板文件。

    Gulp自动化构建

    需求

    使用gulp工具构建项目,主要任务包括scss文件的转化,ECMAScript新特性的转化,还有swig模板页面的转化,并且转化上线的dist包。优化构建过程,提高开发过程的开发效率。图片、字体文件、HTML、JS、CSS文件压缩。

    实现步骤

    1. 安装gulp为开发依赖,创建gukpfile.js。
    2. 实现样式文件的编译。用到的插件是gulp-sass。由于需要使用gulp-useref文件引用处理,所以我们先将编译的文件放到temp文件夹下,经过useref处理后上线的代码放到dist文件夹下面。
    3. 实现脚本文件的编译,需要将ECMAScript新特性进行编译,用到的插件是gulp-babel、@babel/core和@babel/preset-env。gulp-bale只是一个转换平台,所以需要@babel/core和@babel/preset-env进行编译。
    4. 实现模板文件的编译,用到的gulp-swig插件。
    5. 其它文件以及文件的清除,用到的插件是del。我们需要将额外的一些公共文件直接转入dist文件夹下。每次构建时先将dist文件夹删除。
    6. 图片和字体文件转换压缩,用到的插件是gulp-imagemin。由于使用了多个gulp插件,一个一个的引入比较繁琐,所以我们使用gulp-load-plugins插件。
    7. 我们需要一个支持热更新的开发服务器用于调试我们的项目,用gulp来管理这个服务器,这样子后续我们在修改代码时可以自动编译、自动刷新浏览器页面,提高我们的开发效率,减少重复性操作。这里需要用到gulp的watch方法,来监视我们的文件,如果有更新就执行相应的任务,达到热更新的目的。
    8. 优化我们的构建过程。在开发阶段,image、font等资源可以直接使用原目录下的文件,这样子可以加快我们在开发过程中的构建效率。是代码中的develop任务,在开发中使用。
    9. 还需要创建编译后线上版本的任务,需要先清除,然后再编译样式、脚本、页面文件后使用useref通过构建注释解决线上版本文件引用的问题,同时将线上版本的html css js文件压缩,后同时将压缩后的图片、字体文件和其他公共文件编译到dist文件夹里面。具体为代码中的build任务,构建线上版本使用。
    10. 测试完成。

    具体插件

    gulp-sass gulp-babel gulp-clean gulp-clean gulp-swig gulp-imagemin gulp-load-plugins gulp-useref browser-sync gulp-htmlmin gulp-uglify gulp-clean-css gulp-if等。

    实现完整代码

    // gulpfile.js
    const { src, dest, series, parallel, watch } = require("gulp");
    const loadPlugins = require("gulp-load-plugins");
    const plugins = loadPlugins();
    const del = require("del");
    const browserSync = require("browser-sync");
    
    const bs = browserSync.create();
    // 模拟数据
    const data = {
      menus: [
        {
          name: "Home",
          icon: "aperture",
          link: "index.html",
        },
        {
          name: "Features",
          link: "features.html",
        },
        {
          name: "About",
          link: "about.html",
        },
        {
          name: "Contact",
          link: "#",
          children: [
            {
              name: "Twitter",
              link: "https://twitter.com/w_zce",
            },
            {
              name: "About",
              link: "https://weibo.com/zceme",
            },
            {
              name: "divider",
            },
            {
              name: "About",
              link: "https://github.com/zce",
            },
          ],
        },
      ],
      pkg: require("./package.json"),
      date: new Date(),
    };
    
    // 清除dist文件夹
    const clean = () => {
      return del(["dist", "temp"]);
    };
    
    // 样式编译
    const style = () => {
      // 读取src下面所有的scss文件,为其设置基准路径为src,保留src后面的目录结构
      return src("src/assets/styles/*.scss", { base: "src" })
        .pipe(plugins.sass({ outputStyle: "expanded" })) // 用sass编译scss文件,输出样式为完全展开
        .pipe(dest("temp"))
        .pipe(bs.reload({ stream: true })); // 每次编译后调用bs的reload方法,以stream流的形式
    };
    // 脚本编译
    const script = () => {
      return src("src/assets/scripts/*.js", { base: "src" })
        .pipe(plugins.babel({ presets: ["@babel/preset-env"] }))
        .pipe(dest("temp"))
        .pipe(bs.reload({ stream: true }));
    };
    // 模板编译
    const page = () => {
      return src("src/*.html", { base: "src" })
        .pipe(plugins.swig({ data, defaults: { cache: false } }))
        .pipe(dest("temp"))
        .pipe(bs.reload({ stream: true }));
    };
    // 图片压缩
    const image = () => {
      return src("src/assets/images/**", { base: "src" })
        .pipe(plugins.imagemin())
        .pipe(dest("dist"));
    };
    // 字体
    const font = () => {
      return src("src/assets/fonts/**", { base: "src" })
        .pipe(plugins.imagemin())
        .pipe(dest("dist"));
    };
    // 额外的文件
    const extra = () => {
      return src("public/**", { base: "public" }).pipe(dest("dist"));
    };
    
    // 开发服务器启动任务
    const serve = () => {
      // 监视路径下文件如果发生变化就去执行相应的任务
      watch("src/assets/styles/*.scss", style);
      watch("src/assets/scripts/*.js", script);
      watch("src/*.html", page);
      watch(
        ["src/assets/images/**", "src/assets/fonts/**", "public/**"],
        bs.reload
      );
      // 初始化
      bs.init({
        notify: false,
        port: 2080,
        // 监视dist文件夹下的所有文件夹会自动更新网页
        // files: "dist/**",
        server: {
          // 设置网站的根目录
          baseDir: ["temp", "src", "public"],
          // 先找routes下有无对应的配置 没有就去baseDir找
          routes: {
            "/node_modules": "node_modules",
          },
        },
      });
    };
    
    const useref = () => {
      return (
        src("temp/*.html", { base: "temp" })
          .pipe(plugins.useref({ searchPath: ["temp", "."] }))
          // 压缩html js css
          .pipe(plugins.if(/\.js$/, plugins.uglify()))
          .pipe(
            plugins.if(
              /\.html$/,
              plugins.htmlmin({
                collapseWhitespace: true,
                minifyCSS: true,
                minifyJS: true,
              })
            )
          )
          .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
          .pipe(dest("dist"))
      );
    };
    
    // src下面的文件编译
    const compile = parallel(style, script, page);
    // 所有任务
    const build = series(
      clean,
      parallel(series(compile, useref), image, font, extra)
    );
    
    const develop = series(compile, serve);
    module.exports = {
      develop,
      build,
      clean,
      compile,
      useref,
    };
    
    

    历史文章传送门

    • 大前端进击之路(一)函数式编程
    • 大前端进击之路(二)JavaScript异步编程
    • 大前端进击之路(番外篇)手写Promise
    • 大前端进击之路(三)ECMAScript新特性
    • 大前端进击之路(四)TypeScript入门基础

    参考


    起源地下载网 » 大前端进击之路(五)|前端工程化之初体验

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元