疑难解析

解析

常见解析问题

  • --display-error-details提供更多的详细信息

npm link找不到他们的依赖

node.js模块的解析算法很简单,从模块所在目录递归向上找寻node_modules目录。

Windows路径

webpack 的配置文件需要时绝对路径,因为 windows 的路径分隔符是\,所以__dirname + "/app/folder"
这样的代码将会出错,从而会导致问题。
需要使用正确的分隔符,如:path.resolve(__dirname, "app/folder")或者path.join(__dirname, "app", "folder")

使用插件

内置插件

通过在webpack配置文件中添加plugins字段来使用插件

1
2
3
4
5
6
7
8
9
var webpack = require("webpack");

module.exports = {
plugins: [
new webpack.ResolverPlugin([
new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
], ["normal", "loader"])
]
};

其余插件

其他非内置插件通过npm或者其它方式来安装

1
npm install component-webpack-plugin

通过下面的方式来使用

1
2
3
4
5
6
var ComponentPlugin = require("component-webpack-plugin");
module.exports = {
plugins: [
new ComponentPlugin()
]
}

当通过npm安装第三方插件时,建议使用这种方式https://www.npmjs.com/package/webpack-load-plugins,
它会检查所有安装的第三方依赖插件并且在你需要用的时候去加载

使用加载器

什么是加载器

加载器是应用于你程序中的资源文件的转换器,它们是将源文件作为参数并返回新的资源的nodejs函数。
例如可以使用加载器让webpack加载CoffeScript或者JSX文件。

加载器特性

  • 加载器可以链式,通过管道来处理资源文件,最后的加载器返回JavaScript文件,其余的加载器可以
    返回任意格式的资源到下一个加载器
  • 加载器可以是同步的也可以是异步的
  • 加载器运行在nodejs中,可以做任何可能做的事。
  • 加载器接受查询参数,可以用于传递配置文件给加载器。
  • 可以在加载器定义中使用表达式或者正则。
  • 加载器可以通过npm下载或发布。
  • Normal modules can export a loader in addition to the normal main via package.json loader.
  • 加载器可以访问配置文件
  • 插件可以提供加载器更多特性
  • 加载器可以产出任意格式的文件
  • 更多

解析加载器

解析加载器和解析模块类似,一个加载器模块即一个导出函数的 node.js模块,通常情况下通过npm
管理加载器,但是也可以将加载器存在程序中。
引用加载器
按照管理,虽然不是要求的,加载器通常命名为xxx-loader,其中xxx就是加载器的名字,比如json-loader
你可以通过全程引用加载器,也可以通过它的简称来引用。
加载器的命名惯例和搜索优先级是在webpack的配置api的resolveLoader.moduleTemplates定义的.
加载器的命名惯例是很有用的,尤其是在require()语句中引用加载器时。
安装加载器
如果加载器在npm中是可获得的,你可以通过以下命令来安装

1
npm install xxx-loader --save

或者

1
npm install xxx-loader --save-dev

使用
在项目中有多种方式使用加载器

  • 通过require声明中明确指定
  • 通过配置文件配置
  • 通过命令行指定
    注意:尽可能避免使用这种方式,如果你希望你的脚本可以同时在nodejs和浏览器中运行,使用
    在配置文件中明确配置加载器的惯例。
    可以通过require语句使用加载器(或者define,require.ensure,等等)。只需要用!将加载器
    和资源分开即可,每一部分都是相对于当前目录。
    可以在配置中写很多个任意加载器通过前缀!的规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    require("./loader!./dir/file.txt");
    // => uses the file "loader.js" in the current directory to transform
    // "file.txt" in the folder "dir".

    require("jade!./template.jade");
    // => uses the "jade-loader" (that is installed from npm to "node_modules")
    // to transform the file "template.jade"
    // If configuration has some transforms bound to the file, they will still be applied.

    require("!style!css!less!bootstrap/less/bootstrap.less");
    // => the file "bootstrap.less" in the folder "less" in the "bootstrap"
    // module (that is installed from github to "node_modules") is
    // transformed by the "less-loader". The result is transformed by the
    // "css-loader" and then by the "style-loader".
    // If configuration has some transforms bound to the file, they will not be applied.

通过配置文件
可以通过正则来在配置文件中绑定加载器

1
2
3
4
5
6
7
8
9
10
11
12
13
{
module: {
loaders: [
{ test: /\.jade$/, loader: "jade" },
// => "jade" loader is used for ".jade" files

{ test: /\.css$/, loader: "style!css" },
// => "style" and "css" loader is used for ".css" files
// Alternative syntax:
{ test: /\.css$/, loaders: ["style", "css"] },
]
}
}

命令行

1
webpack --module-bind jade --module-bind 'css=style!css'

上述命令给.jade文件绑定了 jade 加载器,给 .css 文件班定了 stylecss 加载器。
查询参数
加载器可以通过查询web风格的字符串来指定查询参数,如:url-loader?mimetype=image/png
注:查询字符串的格式要看加载器,具体格式参考加载器文档。大多数的加载器支持普通的查询格式
?key=value&key2=value2)和 JSON 对象(?{"key":"value","key2":"value2"})。

require

1
require("url-loader?mimetype=image/png!./file.png");

配置文件中

1
{ test: /\.png$/, loader: "url-loader?mimetype=image/png" }


1
2
3
4
5
{
test: /\.png$/,
loader: "url-loader",
query: { mimetype: "image/png" }
}

命令行中

1
webpack --module-bind "png=url-loader?mimetype=image/png"

使用

通过npm安装webpacknpm install webpack -g

注意:官网的全局安装webpack只是示范的目的,当你在做真实项目的情况下,安装webpack
作为一个项目依赖是个明智的选择

快速开始

首先我们要了解使用webpack基本命令行的API

创建一个模块化的javascript项目

让我们在javascript通过使用CommonJS语法中创建一些模块。

cat.js

1
2
var cats = ['dave', 'henry', 'martha'];
module.exports = cats;

app.js (入口)

1
2
cats = require('./cats.js');
console.log(cats);

entry point(入口)就是你的程序将会在哪启动,并且webpack将会在哪里跟踪模块之间的依赖关系。

webpack5s
指定webpack的入口并指定输出文件名。

1
webpack ./app.js app.bundle.js

webpack将会读取并分析入口文件以及它的依赖关系(包括传递依赖),之后会打包他们到app.bundle.js中。
现在通过node app.bundle.js就可以看到所打印的内容,当然在浏览器中也是可以运行的。

了解严格模式

webpack是个灵活的打包器,它提供了许多高级的特性,但不是所有的特性都可以通过命令行的这种方式运行,
为了全面的了解webpack的灵活性,需要创建一个配置文件。

项目结构

在真实的项目中,我们会分开不同的源文件到不同的目录,在这个实例中,将源文件放在src,打包出来的
文件放在bin中。

  1. 创建bin和src目录
    1
    2
    mkdir bin
    mkdir src
  1. 将原文件移到src目录

    1
    mv app.js cats.js src
  2. 初始化一个npm项目

    1
    npm init
  3. 安装webpack作为本项目的一个依赖

    1
    npm install --save-dev webpack

移步配置文件

随着你的项目的成长,你的配置文件将会变的复杂,以命令行的方式定义webpack将会变的不灵便,通过
创建配置文件来代替命令行的这种方式。

  1. 创建webpack.config.js
    1
    2
    3
    4
    5
    6
    7
    module.exports = {
    entry: './src/app.js',
    output: {
    path: './bin',
    filename: 'app.bundle.js'
    }
    };

webpack的配置文件是node形式的模块,所以你可以运行各种形式的代码在这里,只要你最后暴露出
一个定义webpack的对象就行。

  1. 运行webpack
    1
    webpack

webpack将会读取配置文件,打包响应的东西,你可以检查该项目就会发现项目多出bin目录,并且
包含了输出文件

  1. 运行bin/app.bundle.j
    1
    2
    node bin/app.bundle.js
    ["dave", "henry", "martha"]

也可以require()通过npm安装的模块而不需要额外的配置文件。

使用加载器

webpack本身只支持javascript模块,但是很多人会使用转换器去转换ES6、CoffeScript、TypeScript、
等等,这些可以通过wenbpack的loaders实现。
loaders是一些特殊的模块,webpack使用他们来加载其余的模块到javascript中,比如babel-loader使用
Babel去加载ES2015(ES6)的文件。
loaders可以链式化(loaders链),有时你需要加载器链一起工作,比如yaml-loader只能转换YAML到json
中,所以需要json-loader继续转化才能被使用

用babel-loader转换ES2015

在这个例子中,我们告诉webpack通过使用Babel我们可以使用ES2015的特性

  1. 安装babel以及babel的预装配置

    1
    npm install --save-dev babel-core babel-preset-es2015
  2. 安装babel-loader

    1
    npm install --save-dev babel-loader
  3. 通过添加.babelrc文件配置Babel使用这些预装配置

    1
    { "presets": [ "es2015" ] }
  4. 修改webpack.config.js通过babel-loader处理所有以.js结尾的文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    module.exports = {
    entry: './src/app.js',
    output: {
    path: './bin',
    filename: 'app.bundle.js',
    },
    module: {
    loaders: [{
    test: /\.js$/,
    exclude: /node_modules/,
    loader: 'babel-loader',
    }]
    }
    }

我们排除了node_modules文件夹,否则所有的外部库都会经过 Babel,会减慢编译速度**
(5). 安装你想要使用的外部库(jQuery)

1
npm install --save jquery babel-polyfill

使用--save代替--save-dev,因为这些库是在运行的时候被使用的,使用babel-polyfill可以是在老的浏览器中使用ES2015
(6). 修改src/app.js

1
2
3
4
5
6
7
8
9
import 'babel-polyfill';
import cats from './cats';
import $ from 'jquery';

$('<h1>Cats</h1>').appendTo('body');
const ul = $('<ul></ul>').appendTo('body');
for (const cat of cats) {
$('<li></li>').text(cat).appendTo(ul);
}

(7). 使用webpack打包这些模块

1
webpack

(8). 添加index.html

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="bin/app.bundle.js" charset="utf-8"></script>
</body>
</html>

使用插件

通常你需要在工作流中做一些额外的处理,很简单的一个例子就是压缩代码这样可以在浏览器中加
载速度变快,这可以通过插件完成,在配置文件中加入压缩插件(uglify plugin)。

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
const webpack = require('webpack');

module.exports = {
entry: './src/app.js',
output: {
path: './bin',
filename: 'app.bundle.js',
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
}]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
output: {
comments: false,
},
}),
]
}

压缩插件已经包含在webpack的配置文件中,所以你不需要添加额外的模块,你可以写自己的插件,
在这个案例中将文件大小由1618bytes压缩到了308bytes。

安装webpack

  • 安装nodejs
  • 通过npm安装webpack,全局安装webpack npm install webpack -g
  • 在项目中使用webpack

    最好的做法是在项目中使用webpack,这样的话你可以选择基于本项目的webpack版本,不用被强制
    的去使用全局webpack。如果你不想发布你的项目到npm上,那么npm init之后的问题不重要。
    安装并且将webpack加入到package.json中去npm install webpack --save

版本

webpack有稳定版和测试(beta)版本(公测),beta版本在版本号中添加了-beta的标识,beta版本
包含了许多不稳定的变更或实验性的特性在里面并且测试的较少,正式项目中应该用稳定版本。

Dev Tools(开发工具)

npm install webpack-dev-server --save-dev

webpack是什么

webpack是个模块打包工具,它获取有依赖关系的模块并生成表示这些模块的静态资源

为什么有webpack打包系统

现有的模块打包系统不适合大型的项目(单页面应用),最迫切的原因是因为代码拆分和静态资源
更好的接入模块化,对现有的模块化系统进行扩展,但是无法同时完成以下的所有目标

  • 拆分依赖树,使之成为按需加载
  • 让初始化加载时间更短
  • 每一个静态资源都是一个模块
  • 让第三方库成为模块
  • 尽可能的去定义模块的每一部分
  • 适用于大型项目

webpack有什么不同

webpack有同步与异步两种依赖方式,异步依赖在代码优化之后将会行程一个新的块。
加载器
webpack本身只支持处理javascript,但是加载器可以将其它的资源加载到javascript中去,这样做
每一个资源都是一个模块
智能解析
webpack有一个聪明的解析器可以处理几乎所有的第三方库,它甚至允许带有表达式的依赖,
require("./templates/" + name + ".jade")支持最常用的模块化方式CommonJS和AMD

插件系统

webpack以丰富的插件系统为特色,大多数的特色都是基于这个插件系统的,这允许你根据需要定义webpack
并且以开源的方式来发布通用插件。

前端模块化系统的几种方式

  1. <script>-tag的形式,主要问题有:

    • 全局的变量冲突
    • 按序加载的重要性
    • 解决不同模块、包之间的依赖性
    • 项目庞大的时候,需要写很多很多<script>标签
  2. CommonJS: 同步请求(synchronous):

    这种方式使用同步的require方法去加载依赖模块并返回依赖模块所暴露出的接口,一个模块可以
    通过增加属性到export的对象中或者设置module.exports的值来明确的指定暴露的接口。
    优点:

    1. 服务端模块可以使用
    2. npm上已经有好多使用这种方式的写法
    3. 使用简单
      缺点:
    4. 阻塞式的请求不适用于网络请求,网络请求是异步的
    5. 不能并发的请求多个模块
      实现者:
    • node.js- server-side
    • browserify
    • modules-webmake - compile to one bundle
    • wreq - client-side
      1
      2
      3
      require("../file.js");
      exports.doStuff = function() {};//方式一
      module.exports = someValue;//方式二

3.AMD: 异步(asynchronous)请求

对于浏览器来说同步请求有很多问题(CommonJS)所以引入了一个异步版本(一种定义模块与导出模块的方式)

1
2
3
4
require(["module", "../file"], function(module, file) { /* ... */ });
define("mymodule", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});

优点:

  1. 适用于异步的网络请求
  2. 并发加载模块
    缺点:
  3. 代码不易于维护
    实现者:
  • require.js - client-side
  • curl - client-side

4.ES6 Modules

ES6给javascript增加了一些语言特性,实现了另外的模块化系统
优点:

  1. 易于静态分析
  2. 未来的ES标准
    缺点:
  3. 浏览器原生支持需要时间
  4. 目前这种风格还很少
    1
    2
    3
    import "jquery";
    export function doStuff() {}
    module "localModule" {}

模块加载

模块可以执行在浏览器端,所以它必须从服务端加载到浏览器中去,有两种极端的加载方式:

  1. 一个模块一个请求
    优点:
  • 只有需要的才会被加载
    缺点:
  • 过多的模块会造成网络负载,程序响应过慢
  1. 所有的模块一个请求
    优点:
  • 只有一个请求
    缺点:
  • 不需要的模块也加载了

分块加载

编译模块时,将模块拆分成多个小块,拆分点由开发者定义
同样适用于img css webfont html模板等等

对this的理解

  • this是调用时被绑定的,完全取决于函数的调用位置
  • 调用位置

    调用位置就是函数被调用的位置,要寻找调用位置就要分析调用栈(就是为了到达当前执行位置所
    调用的所有函数)。调用位置就在当前正在执行的函数的前一个调用中。

  • this的绑定规则

  1. 默认绑定
  2. 隐式绑定
  3. 显示绑定
  4. new绑定
  • 判断this(优先级)
  1. 函数是否在new中调用(new 绑定)?如果是的话this绑定的新创建的对象
  2. 函数是否通过call、apply(显示绑定)调用?如果是的话,this绑定的是指定的对象
  3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象
  4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象。

git的常用指令(一)

  • 配置别名
    git config alias.st 'status'
    git st 的作用等于 git status,只对当前仓库有效,如果想配置全局则git config -g alias.st 'status'

  • git rm
    git rm –cached会删除索引中的文件并把它保留到工作目录中,而git rm则会将文件从索引和工作目录中都删除。

  • gitk命令查看提交图