webpack学习(一)

webpack学习(一)

开始

随着前端发展,像grunt、gulp这种构建工具以及webpack这种打包工具,在前端工程化进程中显得尤为重要,所以也促使我们来使用这些技术,本文将使用webpack进行简单的环境搭建,以及对其的一些方法属性做一些介绍。

安装

首先为项目创建一个文件夹,然后输入

1
$ npm init

通过输入一系列相关问题,创建一个package.json文件,接下来运行输入

1
$ npm install webpack --save-dev

把webpack当作依赖保存下来

这里需要注意所在文件夹名字不能为webpack否则会报错

项目目录结构

  • /app
    • main.js
    • component.js
  • /build
    • bundle.js (自动创建)
    • index.html
  • package.json
  • webpack.config.js

我们使用webpack的打包命令在我们的/app里自动创建bundle.js

设置webpack

webpack.config.js

1
2
3
4
5
6
7
8
9
var path = require('path');

module.exports = {
entry: path.resolve(__dirname, 'app/main.js'),
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
};

webpack配置文件属性说明:

  • entry: 配置打包文件的入口,可多个入口文件
  • resolve: 配置文件后缀名
    例如:
    1
    2
    3
    4
    5
    6
    resolve: {
    extensions: ['.js', '.jsx'],
    alias: {
    'react': path.join(nodeModulesPath, 'react/react.js')
    }
    }

配置文件后缀名(extensions)后,加载模块文件可以省略后缀名。
例如:

1
2
3
4
5
// 配置前引用模块
var component = require('./component.js');

// 配置后引用模块
var component = require('./component');

配置项(alias)可以为常用模块配置改属性,可以节省编译搜索的时间

  • output: 配置输出文件的路径和文件名等
  • module(loader): 加载相应模块所需要的加载器
    loader配置项:
    • test: /\.(js|jsx)$/, 使用正则表达式,匹配要处理的文件
    • loader: 'eslint-loader, 加载要使用loader,-loader可以省略
    • include: [path.resolve(__dirname, "src/app")], 把要处理的目录包括进来
    • exclued: [nodeModulesPath], 排除不处理的目录
      目前已有的loader列表:
      https://webpack.github.io/docs/list-of-loaders.html

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module: {
preloaders: [
{
test: /\.(js|jsx)$/,
loader: 'eslint-loader',
include: [path.resolve(__dirname, "src/app")],
exclude: [nodeModulesPath]
}
],
loaders: [
{
test: /\.(js|jsx)$/, // 正则表达式匹配 .js 和 .jsx 文件
loader: 'babel-loader?optional=runtime&stage=0', //对匹配的文件进行处理的loader,`?`后面是加载器所带的参数
exclued: [nodeModulesPath] // 排除node module中的文件
}
]
}

  • plugins: 配置要使用的插件。plugin是比loader功能更强大的插件,能使用更多的wepack api。
    示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    plugins: [
    // 压缩打包的文件
    new webpack.optimize.UglifyJsPlugin({
    compress: {
    warnings: false
    }
    }),
    // 允许错误不打断程序
    new webpack.NoErrorsPlugin(),
    // 把指定文件夹下的文件复制到指定的目录
    new TransferWebpackPlugin([
    {form: 'www'}
    ], path.resolve(__dirname, "src"))
    ]

目前已有的plugins列表:
http://webpack.github.io/docs/list-of-plugins.html

运行编译

现在已经有了配置,我们接着添加需要去编译的文件,首先来完成一个hello world

app/component.js

1
2
3
4
5
6
7
8
9
'use strict';

module.exports = function () {
var element = document.createElement('h1');

element.innerHTML = 'Hello World';

return element;
}

app/main.js

1
2
3
4
5
'use strict'

var component = require('./component.js');

document.body.appendChild(component());

在项目文件夹下,运行

1
$ webpack

/build文件夹下会生成一个bundle.js文件

此时打开/build文件夹下的index.html就可以看到输出的Hello World

设置package.json script

使用命令将webpack添加进依赖

1
$ npm install webpack --save

这里的配置和之前不同,这里是--save,而之前我们配置的是--save-dev,这里一个是将webpack添加进项目的依赖中,一个是添加进了开发依赖中,我们可以从package.json中看出区别

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "learn-webpack-react",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "ArthurFree",
"license": "MIT",
"devDependencies": {
"webpack": "^1.13.2"
},
"dependencies": {
"webpack": "^1.13.2"
}
}

从这里我们就可以看出了package.json文件中两个配置分别对应了两个字段。当开发结束后,我们不再需要此依赖时,就可以将其添加进开发依赖(devDependencies)中。

接下来,我们将编译步骤放到这条指令中:

1
$ npm run build

我们在package.json文件中添加以下内容

1
2
3
"scripts": {
"build": "webpack"
}

这样就可以使用上面的命令进行编译了。

当项目越来越复杂时,我们就可以通过这种将复杂的操作隐藏在scripts里面的方式来简化操作。

npm会找到webpack,npm run会把它临时加到PATH来让我们这条指令工作

设置webpack-dev-server

在项目中,频繁的输入npm run build命令,也显得非常玛法,所以通过webpack-dev-server可以让其一直运行着

首先,我们来安装它

1
$ npm i webpack-dev-server --save

安装完成后,我们需要调整一下package.json文件中的scripts部分

1
2
3
4
5
6
{
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build"
}
}

然后在命令行中运行npm run dev时,会执行dev属性中的值

其中指令配置说明:

  1. webpack-dev-server: 在本机建立一个localhost:8080服务器
  2. --devtool eval: 为你的代码创建源地址。当有任何报错的时候可以让你更加精确地定位到文件和行号
  3. --progress: 显示合并代码进度
  4. --colors: 命令行中显示颜色
  5. --content-base build: 指向设置的输出目录

当你运行npm run dev时,会启动一个服务器,然后监听文件修改,然后自动重新合并代码。
在浏览器中访问http://localhost:8080,就可以看到效果了。

不过这里还有些不足,当我们修改完文件保存后,需要手动的在浏览器中刷新,才能看到最新的结果。
所以我们需要增加一个脚本当发生改变时去自动刷新应用,我们在webpack.config.js文件的配置中增加一个入口点。

1
2
3
4
5
6
7
8
9
10
11
12
13
var path = require('path');

module.exports = {
ertry: [
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8080',
path.resolve(__dirname, 'app/main.js')
],
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js'
},
};

至此,我们已经完成了一个

模块

webpack允许使用不同的模块类型,但是’底层’必须使用同一种实现。

ES6模块

1
import MyModule form './MyModule.js';

CommonJS

1
var MyMoudle = require('./MyModule.js');

AMD

1
2
3
define(['./MyModule.js'], function (MyModue) {

});

文件路径

一个模块会按照它的文件路径来加载,我们在/app文件夹下继续创建项目结构

  • /app
    • /modules
      • MyModule.js
    • main.js
    • utils.js

app/main.js中引入app/modules/Module.js

1
2
3
4
5
// ES6
import MyModule from './modules/MyModule.js'

// CommonJS
var MyModule = require('./modules/MyModule.js')

这里./指相对当前文件路径

然后我们在MyModule.js下引入app/utils

1
2
3
4
5
6
7
8
9
10
11
// ES6 相对路径
import utils from './../utils.js'

// ES6 相对路径
import utils from '/utils.js'

// CommonJS 相对路径
var utils = require('./../utils.js');

// CommonJS 绝对路径
var utils = require('/utils');

相对路径是相对当前目录
绝对路径是相对入口文件,这里是main.js

总结

本文主要是简单配置了webpack开发环境,实现了实际开发中的简单的模块加载以及实时刷新功能。其在开发环境中还有更多的功能可以去使用,所以接下来将继续学习使用webpack,并运用到React中。

参考

webpack和React小书:
https://fakefish.github.io/react-webpack-cookbook/Getting-started.html
WebPack 常用功能介绍:
https://segmentfault.com/a/1190000004172052
资源汇总:
http://cnodejs.org/topic/56ef3edd532839c33a99d00e
webpack(中文):
https://webpack2.leanapp.cn/