前端编程之路

Posted willwillie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端编程之路相关的知识,希望对你有一定的参考价值。

前言:本人作为一个前端小白,梳理一下这段时间开发前端一个页面的过程,希望对自己起到备忘并思考的作用,希望我的经验对于别人也有一点帮助的作用。
由于本文碎碎念的部分过长,导致本文过长。还请读者见谅。—更新中

前端框架

现如今,前端框架也越来越多了,比如ember,angular,以及这里要说到的vuejs.。下面的内容首先要介绍vue.js的原理。

Vue.js ?

  • 原理

vue.js是一个 MVVM 前端框架,(Model / View / ViewModel)
这里的viewModel是什么含义呢?
这意味着我们不需要撰写任何 DOM 操作代码,被绑定增强的 html 模板(<template>)是底层数据状态的声明式的映射,数据不过是普通 javascript 对象。我们的视图完全由数据驱动。
这里写图片描述
vue将普通的对象(也就是js的普通的对象)的属性通过Object.defineProperty转换为[ES5特性]之一的 getter/setter。

OBJECT
OBJECT.DEFINEPROPERTY()
该方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。Object.defineProperties()与其一样,只是可以同时定义多个属性。
该方法允许精确添加或修改对象的属性。常用的场景
定义setter和getter。
定义对象属性是否可枚举enumerable。
可枚举的属性键值能够被for inObject.keys获得。
最常见的例子就是,数组中索引属性是可枚举的,而成员方法就是不可枚举的。
~! 这也是为什么我们不要使用for in遍历数组的原因,因为可能有一些拙劣的上下文代码,为数组添加了一个可枚举的方法,因此我们在扩展一个特殊对象属性时特别需要特别关注这一点
OBJECT.KEYS()
把对象的返回一个包括对象可枚举键值的数组。

模板中每个指令/数据绑定 都有一个对应的 watcher 对象, 当修改对象值的时,首先会触发属性的setter,在setter被调用时,会触发 watcher 重新计算 ,也就会导致它的关联指令更新 DOM。
上面的内容把vuejs的内容已说明的很清楚了,如果你能理解指令和数据绑定(下面还会有更多的解释)的话。
Vue.js 的核心是一个响应的数据绑定系统,它让数据与 DOM 保持同步非常简单。在使用 jQuery 手工操作 DOM 时,我们的代码常常是命令式的、重复的与易错的。Vue.js 拥抱数据驱动的视图概念。通俗地讲,它意味着我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。一旦创建了绑定,DOM 将与数据保持同步。每当修改了数据,DOM 便相应地更新。这样我们应用中的逻辑就几乎都是直接修改数据了,不必与 DOM 更新搅在一起。这让我们的代码更容易撰写、理解与维护。

  • 现在重要的问题是用vue来解决问题

比如我想在一个项目里面使用到一个灵活的jsoneditor,通过调研发现vuejs并没有直接的组件可以用,但是发现javascript有一个很好用的叫做jsoneditor的组件,那么我们如何在一个vue.js的工程里面加入这个jsoneditor?

这里就会包括很多要解决的问题了,下面的内容将一一道来。

模块系统

伴随着移动互联的大潮,当今越来越多的网站已经从网页模式进化到了 Webapp 模式。它们运行在现代的高级浏览器里,使用 HTML5、 CSS3、 ES6 等更新的技术来开发丰富的功能,网页已经不仅仅是完成浏览的基本需求,并且webapp通常是一个单页面应用,每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的 JavaScript 代码,这给前端开发的流程和资源组织带来了巨大的挑战。
前端开发和其他开发工作的主要区别,首先是前端是基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。

模块系统主要解决模块的定义、依赖和导出,先来看看已经存在的模块系统。

<script>标签
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>

这是最原始的 JavaScript 文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在 window 对象中。

CommonJS

服务器端的 Node.js 遵循 CommonJS规范,该规范的核心思想是允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过 exportsmodule.exports 来导出需要暴露的接口。

require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;

上面的代码很好理解,但是看起来似乎能解决的问题并不多。那么期望的模块系统是什么样子的呢?

webpack

webpack 就是一个很好的模块化系统。

  • 可以兼容多种模块风格,尽量可以利用已有的代码,不仅仅只是 JavaScript 模块化,还有 CSS、图片、字体等资源也需要模块化。
  • 前端模块是怎么加载的呢?前端模块要在客户端中执行,所以他们需要增量加载到浏览器中。模块的加载和传输,我们首先能想到两种极端的方式,一种是每个模块文件都单独请求,另一种是把所有模块打包成一个文件然后只请求一次。显而易见,每个模块都发起单独的请求造成了请求次数过多,导致应用启动速度慢;一次请求加载所有模块导致流量浪费、初始化过程慢。这两种方式都不是好的解决方案,它们过于简单粗暴。分块传输,按需进行懒加载,在实际用到某些模块的时候再增量更新,才是较为合理的模块加载方案。要实现模块的按需加载,就需要一个对整个代码库中的模块进行静态分析、编译打包的过程
  • 所有资源都是模块:在上面的分析过程中,我们提到的模块仅仅是指JavaScript模块文件。然而,在前端开发过程中还涉及到样式、图片、字体、HTML 模板等等众多的资源。这些资源还会以各种方言的形式存在,比如 coffeescript、 less、 sass、众多的模板库等等。如果他们都可以视作模块,并且都可以通过require的方式来加载,将带来优雅的开发体验,比如:require("./style.css");
    require("./style.less");
    require("./template.jade");
    require("./image.png");

静态分析

如何做到让 require 能加载各种资源呢?在编译的时候,要对整个代码进行静态分析,分析出各个模块的类型和它们依赖关系,然后将不同类型的模块提交给适配的加载器来处理。比如一个用 LESS 写的样式模块,可以先用 LESS 加载器将它转成一个CSS 模块,在通过 CSS 模块把他插入到页面的 <style> 标签中执行。

Webpack 是一个模块打包器。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。Webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。

NODE_ENV

通过NODE_ENV可以来设置环境变量(默认值为development)。
一般我们通过检查这个值来分别对开发环境和生产环境下做不同的处理。可以在命令行中通过下面的方式设置这个值:

linux & mac: export NODE_ENV=production
windows: set NODE_ENV=production
比方说如果代码中要对生产环境下做一些处理,可以这样写:

if (process.env.NODE_ENV === 'production') {
    // just for production code
}

express结合webpack实现hmr

webpack 和 Express 实现前后端热更新开发。
比如在package.json使用到的这两块的版本号是:

"webpack-dev-middleware": "^1.6.1"
"webpack-hot-middleware": "^2.10.0"

Webpack dev middleware 是 WebPack 的一个中间件。它用于在 Express 中分发需要通过 WebPack 编译的文件。单独使用它就可以完成代码的热重载(hot reloading)功能。

Webpack hot middleware 它通过订阅 Webpack 的编译更新,之后通过执行 webpack 的 HMR api 将这些代码模块的更新推送给浏览器端。
那么什么是是HMR api呢?

HMR 即 Hot Module Replacement 是 Webpack 一个重要的功能。它可以使我们不用通过手动地刷新浏览器页面实现将我们的更新代码实时应用到当前页面中
不需要手动刷新浏览器看起来是非常高级的功能,那么这个功能是怎么做到的呢?
HMR 的实现原理是在我们的开发中的应用代码中加入了 HMR Runtime,它是 HMR 的客户端(浏览器端
client)用于和开发服务器通信,接收更新的模块。服务端工作就是前面提到的 Webpack hot middleware
的,它会在代码更新编译完成之后通过以 json 格式输出给HMR Runtime 就会更具 json 中描述来动态更新相应的代码。

这里写图片描述

那么怎么配置这样的热加载环境呢?
我们知道webpack是用来配置输入输出的,那在这个环节之中输入一些小小的魔法,便可以达到我们的的这一目的了。
是怎样的魔法呢,看下面的代码:

var webpack = require('webpack')
...

module.exports = merge(baseWebpackConfig, {
     ...
   entry: [
       // 添加一个和HotMiddleWare通信的客户端
    HotMiddleWareConfig,
    // 添加web应用入口文件
    './client.js'
  ],
  plugins: [
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
  ]
})

getEntries 是自动根据我们规则获取到入口文件并加上 webpack hot middle 配置

express

在 Express 的配置主要就4个步骤:
引入 webpack 的配置文件和 生成 webpack 的编译器
将编译器连接至 webpack dev middleware
将编译器连接至 webpack hot middleware
定义 express 配置

为了提供诸如图像、CSS 文件和 JavaScript 文件之类的静态文件,请使用 Express 中的 express.static内置中间件函数。express.static是一个内置的中间件

app.use(express.static('public'));

现在,可以装入位于 public 目录中的文件:

http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html

Express 相对于静态目录查找文件,因此静态目录的名称不是此 URL 的一部分。

app.use(express.static('public'));
app.use(express.static('files'));

要为 express.static 函数提供的文件创建虚拟路径前缀(路径并不实际存在于文件系统中),请为静态目录指定安装路径,如下所示:

app.use('/static', express.static('public'));

现在,可以装入具有 /static 路径前缀的 public 目录中的文件。


http://localhost:3000/static/images/kitten.jpg
http://localhost:3000/static/css/style.css
http://localhost:3000/static/js/app.js
http://localhost:3000/static/images/bg.png
http://localhost:3000/static/hello.html

path

Node.js path 模块提供了一些用于处理文件路径的小工具,我们可以通过以下方式引入该模块:

var path = require("path")

path.join([path1][, path2][, …])
用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是”/”,Windows系统是”\\”。

npm run

最后在package.json定义一些scripts,就可以使用npm run来运行了。

 "scripts": {
    "dev": "node build/dev-server.js",
    "build": "node build/build.js"
  }

那么npm run的具体用法是怎样的呢?
语法:

npm run-script <command> [-- <args>...]

alias: npm run

来自官方文档的具体用法:

This runs an arbitrary command from a package’s “scripts” object. If no “command” is provided, it will list the available scripts. run[-script] is used by the test, start, restart, and stop commands, but can be called directly, as well. When the scripts in the package are printed out, they’re separated into lifecycle (test, start, restart) and directly-run scripts.
可以运行像上面定义的那样的scripts对象的任何一个命令。如果没有任何命令被指定,它就会列出所有可用的脚本。run[-script]可以用于测试,开始、重启、和结束的命令;也可以直接使用。(这里的生命周期是什么含义?)
也就是说npm run test和npm run start是可以的命令。当然也可以直接用成npm test和npm start这样子的。
也就是说我们定义的任务脚本是有生命周期的。

As of npm@2.0.0, you can use custom arguments when executing scripts. The special option – is used by getopt to delimit the end of the options. npm will pass all the arguments after the – directly to your script:
对于2.0版本以上的npm,你可以使用自定义的参数,–是作为参数的最后的分隔符的。

npm run test – –grep=”pattern”
The arguments will only be passed to the script specified after npm run and not to any pre or post script.
这个参数只会传递给npm
关于node,后续还有更深入的剖析。

常见的loader和作用

Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,返回转换的结果。这样,我们就可以通过 require 来加载任何类型的模块或文件,比如 CoffeeScript、 JSX、 LESS 或图片。
Loader 本身也是运行在 node.js 环境中的 JavaScript 模块,它通常会返回一个函数。大多数情况下,我们通过 npm 来管理 loader,但是你也可以在项目中自己写 loader 模块

通常在webpack.config.js的module.exports中导出的对象中:
比如css loader

module: {
    loaders: [
      {test: /\\.css$/, loader: 'style-loader!css-loader'}
    ]
  }

Adds CSS to the DOM by injecting a <style> tag
npm install style-loader –save-dev
style-loader的用法如何?
It’s recommended to combine it with the css-loader: require(“style-loader!css-loader!./file.css”).
add rules in file.css to document
The css-loader interprets @import and url() like import/require() and will resolve them.
Loader 可以通过管道方式链式调用,每个 loader 可以把资源转换成任意格式并传递给下一个 loader ,但是最后一个 loader 必须返回 JavaScript。
loader 一般以 xxx-loader 的方式命名,xxx 代表了这个 loader 要做的转换功能,比如 json-loader。
Loader 可以在 require() 引用模块的时候添加,也可以在 webpack 全局配置中进行绑定,还可以通过命令行的方式使用。

加载 CSS 需要 css-loader 和 style-loader,他们做两件不同的事情,css-loader会遍历 CSS 文件,然后找到 url() 表达式然后处理他们,style-loader 会把原来的 CSS 代码插入页面中的一个 style 标签中。

require(“!style-loader!css-loader!./style.css”)

因为本文要将的是vue.js,所以下面还会仔细分析vue-loader。
在webpack中加入:

{
        test: /\\.vue$/,
        loader: 'vue'
      },

而vue-loader的定义:

module.exports = function (content) {
  this.cacheable()
  var isServer = this.target === 'node'
  var isProduction = this.minimize || process.env.NODE_ENV === 'production'

  var loaderContext = this
  var query = loaderUtils.getOptions(this) || {}
  var options = this.options.__vueOptions__ = Object.assign({}, this.options.vue, this.vue, query)
  var rawRequest = getRawRequest(this, options.excludedPreLoaders)

  var filePath = this.resourcePath
  var fileName = path.basename(filePath)

  var context = (this._compiler && this._compiler.context) || this.options.context || process.cwd()
  var moduleId = 'data-v-' + genId(filePath, context, options.hashKey)

  var cssLoaderOptions = ''
  if (!isProduction && this.sourceMap && options.cssSourceMap !== false) {
    cssLoaderOptions += '?sourceMap'
  }
  '''
   // final export
    if (options.esModule) {
      output += '\\nexports.__esModule = true;\\nexports["default"] = Component.exports\\n'
    } else {
      output += '\\nmodule.exports = Component.exports\\n'
    }
  } else {
    // inject-loader support
    output =
      '\\n/* dependency injection */\\n' +
      'module.exports = function (injections) {\\n' + output + '\\n' +
      '\\nreturn Component.exports\\n}'
  }

  // done
  return output
}

除此之外,还需要了解的两个loader分别是url-loader和babel-loader.
url-loader的实现源码如下:


    var limit = (this.options && this.options.url && this.options.url.dataUrlLimit) || 0;
    if(query.limit) {
        limit = parseInt(query.limit, 10);
    }
    var mimetype = query.mimetype || query.minetype || mime.lookup(this.resourcePath);
    if(limit <= 0 || content.length < limit) {
        return "module.exports = " + JSON.stringify("data:" + (mimetype ? mimetype + ";" : "") + "base64," + content.toString("base64"));
    } else {
        var fileLoader = require("file-loader");
        return fileLoader.call(this, content);
    }
}
module.exports.raw = true;

作为url-loader的package.json的文件中,就已经有这些依赖了:

 "dependencies": {
    "loader-utils": "^1.0.2",
    "mime": "1.3.x"
  },
  "peerDependencies": {
    "file-loader": "*"
  },

而file-loader的源码是像这样:

var publicPath = "__webpack_public_path__ + " + JSON.stringify(url);
    if (config.publicPath !== false) {
        // support functions as publicPath to generate them dynamically
        publicPath = JSON.stringify(
            typeof config.publicPath === "function"
            ? config.publicPath(url)
            : config.publicPath + url
        );
    }

    if (query.emitFile === undefined || query.emitFile) {
        this.emitFile(outputPath, content);
    }

    return "**module.exports** = " + publicPath + ";";

var url = require(“file-loader!./file.png”);
// => emits file.png as file in the output directory and returns the
public url //
=> returns i. e. “/public-path/0dcbbaa701328a3c262cfd45869e351f.png”

The url loader works like the file loader, but can return a Data Url if the file is smaller than a byte limit.The limit can be specified with a query parameter. (Defaults to no limit,没有限制最好了,最大的文件也会被潜入到网页中)

If the file is greater than the limit (in bytes) the file-loader is used and all query parameters (url查询参数)are passed to it.

网页优化的一大首要任务是减少HTTP 请求 (http request) 的次数,例如通过合并多个JS文件,合并CSS样式文件。除此之外,还有一个data URL 的密技,让我们直接把图像的内容崁入网页里面,这个密技的官方名称是 data URI scheme
(哈哈,如果用url-loader的话,我的那个文件请求就能得到正确的格式)(在本地内存中加载)

不然就会报错(变成了相关的请求报错,因为其实就是本地文件而已)

This package allows transpiling JavaScript files using Babel and webpack.

  • babel
    This package allows transpiling JavaScript files using Babel and webpack.Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。你可以现在就用ES6编写程序,而不用担心现有环境是否支持

  • markdown-highlight-loader;

安装

$ npm i -S markdown-highlight-loader

使用npm 安装,出入的参数是i 和-S i代表可能是install -S代表的应该是save…

用法其实很简单:

/*
include highlight.js theme styles, for example in "vendor" chunk:
entry: {
    vendor: [
        …
        'highlight.js/styles/railscasts.css'
    ],
    …
}
*/
module: {
    loaders: [ {
        test: /\\.md$/,
        loader: 'html!markdown-highlight'
        // loader: 'html!markdown-highlight?+breaks&-smartLists'
    } ]

hightlight的作用,使得代码高亮

更加简单的,如果不需要代码高亮的,直接使用markdown就好了:

{
    module: {
        rules: [{
                test: /\\.md$/,
                use: [
                    {
                        loader: "html-loader"
                    },
                    {
                        loader: "markdown-loader",
                        options: {
                            /* your options here */
                        }
                    }
                ]
            }]
    }
}

插件系统

Webpack 还有一个功能丰富的插件系统。大多数内容功能都是基于这个插件系统运行的,还可以开发和使用开源的 Webpack 插件,来满足各式各样的需求。
插件可以完成更多loader不能完成的功能。
插件的会用一般是在webpack的配置信息plugins选项中指定。
我们利用一个最简单的 BannerPlugin 内置插件来实践插件的配置和运行,这个插件的作用是给输出的文件头部添加注释信息。

var webpack = require('webpack')
module.exports = {
  entry: './entry.js',
  output: {
    path: __dirname,
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {test: /\\.css$/, loader: 'style-loader!css-loader'}
    ]
  },
  plugins: [
    new webpack.BannerPlugin('This file is created by zhaoda')
  ]
}

再比如第三方插件extract-text-webpack-plugin:Extract text from bundle into a file.

for webpack 2
npm install –save-dev extract-text-webpack-plugin
for webpack 1
npm install –save-dev extract-text-webpack-plugin@1.0.1
const ExtractTextPlugin = require(“extract-text-webpack-plugin”);

module.exports = {
module: {
rules: [
{
test: /.css$/,
use: ExtractTextPlugin.extract({
fallback: “style-loader”,
use: “css-loader”
})
}
]
},
plugins: [
new ExtractTextPlugin(“styles.css”),
]
}这个插件的作用是什么呢?它会将所有通过require("style.css")s的entry块放到一个单一的css文件中去,使得你的styles不再嵌入到JS文件中,如果你的所有的css量很大,这会更快(因为css bundle是并行的导入到js bundle中去的)

node

node涉及到的知识点比较少。

node 模块和应用

  • Node应用由模块组成,采用CommonJS模块规范。根据这个规范,每个文件就是一个模块,有自己的作用域,Node内部提供一个Module构建函数所有模块都是Module的实例。
    module.id 模块的识别符,通常是带有绝对路径的模块文件名。
    module.filename 模块的文件名,带有绝对路径。
    module.loaded 返回一个布尔值,表示模块是否已经完成加载。
    module.parent 返回一个对象,表示调用该模块的模块。
    module.children 返回一个数组,表示该模块要用到的其他模块。
    **module.exports 表示模块对外输出的值。**

    npm做nodejs的包依赖管理,bower做javascript的包依赖管理

  • javascript的import 语句用于导入从外部模块,另一个脚本等导出的函数,对象或原语。

  • 关于默认导出方式,每个模块只有一个默认导出。一个默认导出可以是一个函数,一个类,一个对象等。当最简单导入的时候,这个值是将被认为是”入口”导出值。export default{} 对于只导出一部分的值来说 命名导出的方式很有用。。。在导入时候,可以使用相同的名称来引用对应导出的值。
  • require
    最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了。后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载。下面的网页代码,相信很多人都见过。
      <script src="1.js"></script>
      <script src="2.js"></script>

     这段代码依次加载多个js文件。
    这样的写法有很大的缺点。首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。require.js的诞生,就是为了解决这两个问题。

node核心功能

如果只是在服务器运行JavaScript代码,用处并不大,因为服务器脚本语言已经有很多种了。Node.js的用处在于,它本身还提供了一系列功能模块,与操作系统互动。这些核心的功能模块,不用安装就可以使用,下面是它们的清单。

http:提供HTTP服务器功能
url:解析URL
fs:与文件系统交互。
querystring:解析URL的查询字符串
child_process:新建子进程
util:提供一系列实用小工具
path:处理文件路径(就像上面所提到过的那样)
crypto:提供加密和解密功能,基本上是对OpenSSL的包装

上面这些核心模块,源码都在Node的lib子目录中。为了提高运行速度,它们安装时都会被编译成二进制文件。
核心模块总是最优先加载的。如果你自己写了一个HTTP模块,require(‘http’)加载的还是核心模块。

var path = require('path')
var express = require('express')
var webpack = require('webpack')

比如上面的path就是nodejs内置的核心功能,express和webpack是第三方的一些模块,功能非常强大,像上面所论述的那样。

node命令的使用

node可以直接写node命令行。
安装完成之后,直接运行 node 命令就可以启动 node.js 提供的命令行。在命令行中可以直接输入 JavaScript 代码并运行。也可以通过 node server.js 的方式来运行一个 JavaScript 文件 server.js 。
比如:

D:\\code\\trunk\\webapps\\sysman-web>node
> var path = require('path')
undefined
> path
{ resolve: [Function: resolve],
  normalize: [Function: normalize],
  isAbsolute: [Function: isAbsolute],
  join: [Function: join],
  relative: [Function: relative],
  _makeLong: [Function: _makeLong],
  dirname: [Function: dirname],
  basename: [Function: basename],
  extname: [Function: extname],
  format: [Function: format],
  parse: [Function: parse],
  sep: '\\\\',
  delimiter: ';',
  win32: [Circular],
  posix:
   { resolve: [Function: resolve],
     normalize: [Function: normalize],
     isAbsolute: [Function: isAbsolute],
     join: [Function: join],
     relative: [Function: relative],
     _makeLong: [Function: _makeLong],
     dirname: [Function: dirname],
     basename: [Function: basename],
     extname: [Function: extname],
     format: [Function: format],
     parse: [Function: parse],
     sep: '/',
     delimiter: ':',
     win32: [Circular],
     posix: [Circular] } }

再比如express就更了不得了:


> var express = require('express')
undefined
> express
{ [Function: createApplication]
  application:
   { init: [Function: init],
     defaultConfiguration: [Function: defaultConfiguration],
     lazyrouter: [Function: lazyrouter],
     handle: [Function: handle],
    。。。
  request:
   IncomingMessage {
     header: [Function: header],
     get: [Function: header],
   。。。
  response:
   ServerResponse {
     status: [Function: status],
     links: [Function],
   。。。
  Route: [Function: Route],
  Router:
   { [Function]
     param: [Function: param],
     handle: [Function: handle],
  。。。
  query: [Function: query],
  static:
   { [Function: serveStatic]
     mime:
      Mime {
        types: [Object],
        extensions: [Object],
        default_type: 'application/octet-stream',
        Mime: [Function: Mime],
        charsets: [Object] } } }

在 node.js 可以运行的 JavaScript 代码中,可以使用一些全局的对象:process 、用来加载模块的 require() 方法、 __filename 、 __dirname 和与浏览器中相似的用来执行定时任务的 setTimeout() 和 setInterval() 方法等,[具体参考]https://nodejs.org/docs/latest/api/synopsis.html(https://nodejs.org/docs/latest/api/globals.html#globals_dirname)

node [options] [v8 options] [script.js | -e "script"] [arguments]

process对象是Node的一个全局对象,提供当前Node进程的信息。它可以在脚本的任意位置使用,不必通过require命令加载。

proxy:http-proxy-middleware

用法,比如:

var express = require('express');
var proxy = require('http-proxy-middleware');

var app = express();

app.use('/api', proxy({target: 'http://www.example.org', changeOrigin: true}));
app.listen(3000);

这个表示代理/ api请求到http://www.example.org

var proxy = require('http-proxy-middleware');

var apiProxy = proxy('/api', {target: 'http://www.example.org'});
//                   \\____/   \\_____________________________/ 
//                     |                    | 
//                   context             options 

// 'apiProxy' is now ready to be used as middleware in a server. 

context:确定应将哪些请求代理到目标主机。 (更多关于上下文匹配)
options.target:目标主机到代理。 (协议+主机)

ring和compojure

compojure是用作路由作用的。

(GET "/user/:id" [id] (str "hello user " id ""))

routes 返回值为 Ring-handler 函数。
匹配 HTTP 方法 – GET

compojure 定义了一系列 route 宏,包括 POST,PUT,DELETE,OPTIONS,PATCH 和 HEAD。如果要匹配任何一种 HTTP request ,可以使用 ANY。注意:这些宏全部都是大写。

匹配 URI – “/user/:id”

这个字符串用于定义 routing(语法来自于 Clout 模块),很多语法格式同 Ruby on Rails 和 Sinatra 一致。
:id 将匹配 /user/ 后的所有余下部分,结果存入 “id” 参数。
如果 URI 不匹配定义的路径,route 函数将返回 nil。

包管理器 npm

  • –save

    当你为你的模块安装一个依赖模块时,正常情况下你得先安装他们(在模块根目录下npm install
    module-name),然后连同版本号手动将他们添加到模块配置文件package.json中的依赖里(dependencies)。

    -save和save-dev可以省掉你手动修改package.json文件的步骤。 npm install module-name -save 自动把模块和版本号添加到dependencies部分 npm install module-name -save-dev 自动把模块和版本号添加到devdependencies部分

  • package.json
    dependencies部分:字段指定了项目运行所依赖的模块
    devdependencies部分:字段指定了项目开发所依赖的模块

If someone is planning on downloading and using your module in their program, then they probably don’t want or need to download and build the external test or documentation framework that you use.In this case, it’s best to map these additional items in a devDependencies object.
如果有人想下载并使用你的模块,但是他们可能不想或者不需要下载或安装额外的文档框架。就最好使用devDependencies 这个对象。
These things will be installed when doing npm link or npm install from the root of a package, and can be managed like any other npm configuration param. See npm-config for more on the topic.
For build steps that are not platform-specific, such as compiling CoffeeScript or other languages to JavaScript, use the prepare script to do this, and make the required package a devDependency.
这写东西会在安装的时候就用npm安装到package的root下面。

这两者的区别?
npm install 在安装 npm 包时,有两种命令参数可以把它们的信息写入 package.json 文件:

–save
–save-dev
但它的文档里1,只提到一个小区别,–save 会把依赖包名称添加到 package.json 文件 dependencies 键下,–save-dev 则添加到 package.json 文件 devDependencies 键下。
。它们真正的区别是,devDependencies 下列出的模块,是我们开发时用的,比如 grunt-contrib-uglify,我们用它混淆 js 文件,它们不会被部署到生产环境。dependencies 下的模块,则是我们生产环境中需要的依赖。

dependencies配置的依赖是在正常运行(一般为生产环境)该包时必须要的依赖项

什么意思?很简单,就是假设你的包被别人依赖了,那么别人在安装你的包时会自动安装你的包里的dependencies中配置的这些依赖包,也就是说你的包没有这些包就不能正常使用。

devDependencies配置的依赖是你在开发你的包时安装的一些在生产环境非必要的依赖项。

那什么是生产环境非必要的依赖项?比如说:你想使用mocha来测试你的包,那么就可以安装mocha到devDependencies,而不是dependencies,因为他不是生产环境所必须的。依赖你的包的人,是想依赖你的核心代码,而不是需要使用你包里的mocha

CSS /LESS/stylus

Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充。

stylus 是一个CSS的预处理框架,2010年产生,来自Node.js社区,主要用来给Node项目进行CSS预处理支持,所以 Stylus 是一种新型语言,可以创建健壮的、动态的、富有表现力的CSS。比较年轻,其本质上做的事情与 SASS/LESS 等类似,应该是有很多借鉴,所以近似脚本的方式去写CSS代码。Stylus默认使用 .styl 的作为文件扩展名,支持多样性的CSS语法。

全局安装:
npm install stylus -g

比如&就是一个非常灵活的用法:

ul
    li a
        display: block
        color: blue
        padding: 5px
        html.ie &
            padding: 6px
        &:hover
            color: red

编译为css:

ul li a {
  display: block;
  color: #00f;
  padding: 5px;
}
html.ie ul li a {
  padding: 6px;
}
ul li a:hover {
  color: #f00;
}

下面具体一点:

就CSS本身而言,对于大多数Web前端从业人员来说就不是问题。学过CSS的人都知道,它不是一种编程语言。你可以用它开发网页样式,但是没法用它编程。换句话说,CSS基本上是设计师的工具,不是程序员的工具。在程序员的眼里,CSS是很头痛的事情,它并不像其它程序语言,比如说php、Javascript等等,有自己的变量、常量、条件语句以及一些编程语法,只是一行行单纯的属性描述,写起来相当的费事,而且代码难易组织和维护。

很自然的,有人就开始在想,能不能给CSS像其他程序语言一样,加入一些编程元素,让CSS能像其他程序语言一样可以做一些预定的处理。这样一来,就有了“CSS预处器(CSS
Preprocessor)”。
一、什么是CSS预处器

CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行编码工作。通俗的说,CSS预处理器用一种专门的编程语言,进行Web页面样式设计,然后再编译成正常的CSS文件,以供项目使用。CSS预处理器为CSS增加一些编程的特性,无需考虑浏览器的兼容性问题,例如你可以在CSS中使用变量、简单的逻辑程序、函数等等在编程语言中的一些基本特性,可以让你的CSS更加简洁、适应性更强、可读性更佳,更易于代码的维护等诸多好处。

CSS预处理器技术已经非常的成熟,而且也涌现出了很多种不同的CSS预处理器语言,比如说:Sass(SCSS)、LESS、Stylus、Turbine、Swithch CSS、CSS Cacheer、DT CSS等。如此之多的CSS预处理器,那么“我应该选择哪种CSS预处理器?”也相应成了最近网上的一大热门话题,在Linkedin、Twitter、CSS-Trick、知呼以及各大技术论坛上,很多人为此争论不休。相比过计我们对是否应该使用CSS预处理器的话题而言,这已经是很大的进步了。

到目前为止,在众多优秀的CSS预处理器语言中就属Sass、LESS和Stylus最优秀,讨论的也多,对比的也多。本文将分别从他们产生的背景、安装、使用语法、异同等几个对比之处向你介绍这三款CSS预处理器语言。相信前端开发工程师会做出自己的选择——我要选择哪款CSS预处理器。

less是2009年的一个开源项目,LESS提供了多种方式能平滑的将写好的代码转化成标准的CSS代码,在很多流行的框架和工具中已经能经常看到LESS的身影了(例如Twitter的Bootstrap框架就使用了LESS著作权归作者所有。
Stylus,2010年产生,来自于Node.js社区,主要用来给Node项目进行CSS预处理支持,在此社区之内有一定支持者,在广泛的意义上人气还完全不如Sass和LESS。

[Stylus]被称为是一种革命性的新语言,提供一个高效、动态、和使用表达方式来生成CSS,以供浏览器使用。Stylus同时支持缩进和CSS常规样式书写规则。

Sass、LESS和Stylus源文件(除了LESS源文件在客户端下运行之外)都不能直接被浏览器直接识别,这样一来,要正常的使用这些源文件,就需要将其源文件转译成浏览器可以识别的CSS样式文件,这也是使用CSS预处理器很关键的一步,如果这一步不知道如何操作,那么意味着写出来的代码不可用著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文: https://www.w3cplus.com/css/css-preprocessor-sass-vs-less-stylus-2.html © w3cplus.com
Stylus的语法花样多一些,它的文件扩展名是“.styl”,Stylus也接受标准的CSS语法,但是他也像Sass老的语法规则,使用缩进控制,同时Stylus也接受不带大括号({})和分号的语法,如下所示:

/style.styl/
/类似于CSS标准语法/
h1 {
color: #963;
background-color:#333;
}
/省略大括号({})/
h1
color: #963;
background-color: #333;
/省略大括号({})和分号(;)/
h1
color:#963
background-color:#333
在Stylus样式中,你也可以在同一个样式文件中使用不同的语法规则,下面这样的写法也不会报错:

/style.styl/
h1 {
color #963
}
h2
font-size:1.2em

小区插曲:
早在90年代中期到后期起草的 CSS1规范中就介绍过!important,它能够帮助开发者和用户在修改样式表的时候轻松覆盖原本的权重。著作权归作者所有。
样式的应用依赖具体的情况,一个更加具体的选择器往往会比一个笼统选择器获得更大的权重。
样式的应用依赖样式出现的顺序(即,后面的会覆盖前面的)
从这个提纲中,你可能已经明白!important会如何改变权重以及它在层叠中扮演一个什么样的角色。接下来让我们看一下!important更多的细节。

举一个例子就可以很好的说明了:

语法和描述

!important为开发者提供了一个增加样式权重的方法。应当注意的是!important是对整条样式的声明,包括这个样式的属性和属性值(感谢Brad Czerniak指出其中的差别)。这里有个简单的代码示例可以清晰地说明!important是如何应用于原本的样式中的:

#example {
  font-size: 14px !important;   
}

#container #example {
  font-size: 10px;
}   
在上面的代码示例中,由于使用了!importantid为“example”的元素字号将被设置为14px。

如果不使用!important,第二个样式声明的代码块很自然地比第一个的权重要大,原因有二:在样式表中第二个代码块要比第一个出现的晚(即,它位列第二);第二个代码块有更大的权重(是由两个id#container #example组合而成,而不是只有一个id#example。但是因为第一个代码块里面包含了!important,所以对于字号设置来说它有更大的权重。
以上是关于前端编程之路的主要内容,如果未能解决你的问题,请参考以下文章

大前端进击之路:函数式编程

前端编程之路

大前端进击之路|JavaScript异步编程

5.web前端之路:JavaScript

前端菜鸟的编程之路

译文:18个实用的JavaScript代码片段,助你快速处理日常编程任务