• 前端自动化 模块化开发


    前端自动化 模块化开发

    Grunt


    为什么Grunt

    在前端开发的过程中,我们经常会做一些跟功能、代码无关的重复的事情,比如复制、粘贴、压缩等等,我们需要有一个前端自动化的工具。


    什么是Grunt

    免费的小秘书 Grunt官网


    怎么用Grunt

    • 前提:node npm
    • 安装grunt命令行工具 npm install -g grunt-cli
    • 在工作目录安装grunt npm install grunt --save-dev
    • 编辑Gruntfile.js文件
    • 在命令行执行grunt命令

    关于Gruntfile.js的内容

    格式如下,三步上篮:

    module.exports=function(grunt){//包裹函数,所有代码都在这里
        grunt.initConfig({});//1配置任务内容
        grunt.loadNpmTasks();//2加载插件
        grunt.registerTask();//3注册任务
    }
    

    initconfig——配置
    可以有多个插件名,每个的插件名-加载插件名-注册任务中执行的插件名字要一致。
    每个插件名可以有多个任务描述,默认全部执行,也可以指定执行某些任务。

    grunt.initConfig({
    	插件名1: {
    		任务描述1: {
    			//描述xxx
    		},
    		任务描述2: {
    			//描述xxx2
    		}
    	},
    	插件名2: {
    		任务描述3: {
    			//描述xxx3
    		}
    	}
    });
    比如:
    uglify: {
    	main: {
    		//描述
    		src:	'1.js',//源文件
    		dest:	'1.min.js'//目标文件
    	}
    }
    

    loadNpmTasks——引入插件

    grunt.loadNpmTasks('grunt-contrib-uglify');
    
    关于grunt的插件。。。

    registerTask——注册任务

    grunt.registerTask('default', ['uglify']);
    

    关于执行grunt命令

    执行的是registerTask注册的任务

    Tips:

    • 插件基本都能自动创建文件夹
    • 重复执行grunt的话,已经存在的文件会被覆盖,不报错,不在后面添加。
    • 通配符 *号 代指所有
    • 通配符 **号 代指所有,包括没有
    • cwd 描述想要作为当前文件夹的文件夹路径
    • expand,分开成一个个的文件,uglify可以压缩文件到一个文件,cssmin不可以
    • ext参数,设置后缀名
    • grunt中的模板 <%= grunt.template.today("yyyy-mm-dd HH-MM-ss") %>, 也可以放一个常量json进来可以在模板中使用,避免重复写,也便于更改
      结合<%= %>使用模板
    • grunt输出 grunt > log.txt
    • concat 连接起来,不压缩,生成的是一个文件【注意: 顺序未知】
    • grunt.file上面有基于nodeJs的fs包装好的操作文件的方法,比如:grunt.file.readJSON()通常用来读取json文件,直接转化为可用的json
    • copy 带文件夹层级复制,复制多个文件时,要有expand,否则会报错
    • watch —— 监测,(自动化)

    AMD和CMD

    WHY——模块化编程 vs 原始代码

    转自阮一峰的博客:最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了。后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载。下面的网页代码,相信很多人都见过。

    <script src="1.js"></script>
    <script src="2.js"></script>
    <script src="3.js"></script>
    <script src="4.js"></script>
    <script src="5.js"></script>
    <script src="6.js"></script>
    

    这段代码依次加载多个js文件。随着代码越来越多,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。就算是代码作者本人,在后期维护起来也会越来越吃力,更不敢想多人合作了。

    在前端开发过程中,经常会出现一个单文件几千行甚至近万行的情况。这种大文件,对协作开发、后续维护、性能调优等都不利。模块化开发初衷是帮助前端开发工程师将大文件拆分成小文件,能保持小颗粒度的模块化开发,同时不需要过多考虑依赖关系,让依赖管理轻松自如,将更多精力聚焦在代码本身的逻辑上。

    HOW——AMD和CMD之争

    先分开介绍,再对比
    CMD seaJs 玉伯
    玉伯(王保平),淘宝前端类库 KISSY、前端模块化开发框架SeaJS、前端基础类库Arale的创始人。
    玉伯


    CMD规范的定义

    • 懒加载——Execution must be lazy.
    • 一个模块就是一个文件,代码的书写格式如下:define(factory);
    • define 是一个全局函数,用来定义模块。
    • define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串。
    • factory 为对象、字符串时,表示模块的接口就是该对象、字符串
    • factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module:
    ```
    define(function(require, exports, module) {//参数的顺序必须是这样的
      // 模块代码
      //require是获取其他模块的函数
      //exports用来输出当前模块
      //module用来输出当前模块
      //exports 仅仅是 module.exports 的一个引用。在 factory 内部给 exports 重新赋值时,并不会改变 module.exports 的值。因此给 exports 赋值是无效的,不能用来更改模块接口。
    });
    ```
    
    • 经常使用的 API 只有 define, require, exports, module.exports而已,简单明了

    seaJs的用法

    最简单的seaJs案例

    //主html
    <!doctype html>
    <html>
        <head>
            <script src="../sea-modules/seajs/seajs/2.2.0/sea.js"></script>
            <script>
                seajs.use("main");//main是main.js,是用define定义的模块
            </script>
        </head>
        <body>
        页面内容
        </body>
    </html>
    
    //main.js
    define(function(require) {
        alert(1);
    });
    
    • 主文件配置参数 seajs.config(); 官方介绍
      seajs.config({//paths 配置可以结合 alias 配置一起使用,让模块引用非常方便。 // 设置路径,方便跨目录调用 paths: { 'arale': 'https://a.alipayobjects.com/arale', 'jquery': 'https://a.alipayobjects.com/jquery' }, // 设置别名,方便调用 alias: { 'class': 'arale/class/1.0.0/class', 'jquery': 'jquery/jquery/1.10.1/jquery' } });
    • 主文件使用模块:seajs.use();——头(or衣领)API介绍
      // 加载一个模块 seajs.use('./a'); // 加载一个模块,在加载完成时,执行回调 seajs.use('./a', function(a) { a.doSomething(); }); // 加载多个模块,在加载完成时,执行回调 seajs.use(['./a', './b'], function(a, b) { a.doSomething(); b.doSomething(); });
    • 如何定义模块
      用define来定义模块。Sea.js 推崇一个模块一个文件,遵循统一的写法:
      define(function(require, exports, module) { // 模块代码 // exports 被require的对象上的属性或方法 // 对外提供 foo 属性 // 在外部使用:require(xx).foo exports.foo = 'bar'; // 对外提供 doSomething 方法 // 在外部使用:require(xx).dosomething exports.doSomething = function() {}; //********************// // module.exports 就是被require的对象 module.exports = { name: 'a', doSomething: function() {}; }; });
    • 如何引用模块
      require 用来获取指定模块的接口。
      define(function(require, exports, module) { // 获取模块 a 的接口 var a = require('./a'); // 调用模块 a 的方法 a.doSomething(); });
    • 总结:用define来定义模块,一个模块就是一个文件,在模块里用require来引用其他模块,在主html文件里引入seajs后用seajs.use()来开启js文件。

    AMD requireJs

    AMD规范的定义

    • 全称 Asynchronous Module Definition——异步模块定义规范。
    • 模块和模块的依赖可以被异步加载。
    • 模块的依赖被异步加载完成以后,工厂函数才会执行。
    • define 是一个全局函数,用来定义模块。
    • define 可以接受多种格式的参数,不过通常可以是:
    • define(依赖的数组,工厂函数);
    • define(工厂函数);
    • define(一个对象);
    • 一个模块就是一个文件

    requireJs的用法

    最简单的requireJs案例

    //主html
    <!doctype html>
    <html>
        <head>
            <script src="js/require.js"></script>
            <script>
                require(['jquery'], function($){
                    alert('jquery loaded');
                });
            </script>
        </head>
        <body>
        页面内容
        </body>
    </html>
    

    or:

    //主html
    <!doctype html>
    <html>
        <head>
            <script src="js/require.js" data-main="js/main.js"></script>
        </head>
        <body>
        // 这样写,会异步加载data-main指定的js文件,并把data-main所在的路径作为config配置的baseUrl。如果不想异步,就像上面一样写。
        页面内容
        </body>
    </html>
    //main.js
    require(['jquery'], function($){//会在jquery模块执行完成后,把jquery的输出做为参数传入后面的工厂函数,并执行工厂函数
        alert('jquery loaded');
    });
    
    • 配置: 可以使用require.config来设置依赖的模块的名称和对应的路径,也可以在引入require.js之前定义一个名字为require的json。两种方式都可以进行配置。; requireJs配置官方介绍
      <script src="scripts/require.js"></script> <script> require.config({ baseUrl: "/another/path", paths: { "some": "some/v1.0" } }); require( ["some/module", "my/module"], function(someModule, myModule) { //..... } ); </script> 或者是: <script> var require = { baseUrl: "/another/path", paths: { "some": "some/v1.0" } }; </script> <script src="scripts/require.js"></script>
    • 主文件如何使用模块:从上面已经可以看到,不同于seaJs的使用seajs.use()函数,requireJs使用require()函数来开始执行。
    • 如何定义模块
      用define来定义模块:常见的3种情况
    • define(依赖的数组,工厂函数);
    ```
    define(['aModule','bModule'],function(a,b) {
      // 模块代码
      // 这个定义的模块在被调用时,aModule和bModule模块加载完成之后,才会以他们的返回值作为参数执行工厂函数
    });
    ```
    >> * define(工厂函数); [语法糖](http://requirejs.org/docs/whyamd.html#sugar)
    ```
    define(function(require, exports, module) {
      // 模块代码
      // 这种方式其实是requireJs的语法糖,可以在函数里面用变量接受require过来的模块(就像seaJs做的那样),并不真的是同步require那个代码,而是用的Function.prototype.toString()转换成数组里面的格式(怎么转换的咱们不管)后异步下载后执行回调。
    });
    ```
    >> * define(一个对象);
    ```
    define({
        color: "black",
        size: "12"
    });
    ```
    
    • 如何引用模块
      用require来获取指定模块的接口(常见有2种):
    • require(依赖的数组,工厂函数);
    ```
    require(['aModule','bModule'],function(a,b) {
      // 模块代码
      // aModule和bModule模块加载完成之后,才会以他们的返回值作为参数执行工厂函数
    });
    ```
    >> * require(依赖的数组);
    ```
    //只是用来做一个头,异步引入js后自己不用再做其他事情
    require(['aModule','bModule']) ;
    ```
    
    • 总结:
      用define来定义模块,一个模块就是一个文件。
      define新模块时用数组提前声明依赖的模块。
      在主html文件里引入requirejs后用require()来开启js文件。

    RequireJS 与 SeaJs 的异同

    共同点:

    • 都是模块加载器,倡导模块化开发理念
    • 核心价值是让 JavaScript 的模块化开发变得简单自然

    不同点:

    • RequireJS是异步加载模块,SeaJs是同步加载模块
    • RequireJS是提前声明并加载依赖,SeaJs是按需加载依赖模块

    我们目前使用的是 RequireJS。

  • 相关阅读:
    赫夫曼树相关算法
    用栈来实现 括号匹配 字符序列检验
    二叉树的建立和遍历
    数据结构-算术表达式求值
    构造一个单链表L,其头结点指针为head,编写程序实现将L逆置
    单链表的基本操作(C语言)数据结构
    java代码打印杨辉三角
    无标题
    写一个方法,判断给定的数字是偶数还是奇数
    关于生物信息学与R的相关资料和网站
  • 原文地址:https://www.cnblogs.com/liujunyang/p/4688518.html
Copyright © 2020-2023  润新知