webpack简单介绍, webpack-dev-server的使用, css-loader, style-loader, loader与plugin.

这里是教程需要用到的代码示例

webpack简单介绍

当项目中js文件和css文件很多时, 手动整理这些文件很容易产生混乱和错误, 因此我们可以利用webpack这个构建工具帮我们整理好这些文件.

不使用webpack

下载代码示例, 查看01-starting-app分支, 可以看到index.html引入了两个js文件, app.jsdom-loader.js. 打开中的index.html查看效果, app正常运行.

但是如果我们调换两者在index.html中的引入位置, 会发现app无法正常运行, 因为dom-loader.js中的内容为获取DOM节点, 如果不先于app.js执行, app.js中的一些变量就为undefined.

这个例子比较简单, 可以不使用webpack进行构建, 这里只是将其作为例子说明webpack的基本使用方法, 可是当项目较大, 需要比较多的js文件时, webpack就很有用了.

现在看看在这个例子中如何使用webpack.

使用webpack

  1. 在项目文件夹命令行执行: npm init, 如果不需要额外修改配置可以一路回车, 也能这样简写: npm init -y 设置全部配置为默认值.

    上述步骤执行后会在项目根目录自动创建package.json文件

  2. npm install webpack --save-dev, 也可以这样简写 npm i -D webpack. (国内使用npm速度很慢, 可以使用cnpm)

    执行上述指令后package.json文件会多出下面几行内容:

    1
    2
    3
    "devDependencies": {
    "webpack": "^2.5.1"
    }
  3. 然后在package.json下添加下面内容, 声明webpack的入口及输出文件, 这里入口是app.js.

    1
    2
    3
    "scripts": {
    "build": "webpack src/js/app.js dist/bundle.js"
    }
  4. 同时需要在app.js文件中使用import引入其他依赖的js文件(这里是dom-loader.js), 具体这样修改:

    app.js顶部输入:

    1
    import { secretButton, secretParagraph } from './dom-loader'

    然后在dom-loader.js中:

    1
    2
    export var secretButton = document.querySelector('#secret-button');
    export var secretParagraph = document.querySelector('#secret-paragraph');

    这样, app.js中就引入了dom-loader.js中声明的变量. 我们还没有加入babel来编译ES6的语法, 因此声明变量暂时无法使用letconst.

  5. 之后, 执行npm run build之后就会将所有需要的js文件打包整合到bundle.js中, 在index.html中引入bundle.js文件, 应用就可以正常运行.

    加入-p会优化压缩bundle.js:

    1
    2
    3
    4
    "scripts": {
    "build": "webpack src/js/app.js dist/bundle.js",
    "build-prod": "webpack src/js/app.js dist/bundle.js -p"
    }

直到现在, 我们打开index.html的方式还是直接打开, 利用file协议, 但是在file协议下, 检查Network时, 所有asset的size都为0, 因为所有这些asset都是通过文件系统获取, 如果想要获取真正的size, 需要开启一个服务器, 在localhost或者是http协议下打开. 可以利用webpack-dev-server.

webpack-dev-server

先执行npm install --save-dev webpack-dev-server;

package.json中”build”的值改成下面这样:

1
2
3
"scripts": {
"build": "webpack-dev-server --entry ./src/js/app.js --output-filename ./dist/bundle.js"
}

由于我们对webpack的配置会越来越多, 因此现在开始将webpack的配置信息存储到另外的文件中, 在根目录下创建webpack.config.js, 一般来说是使用该名称, webpack会直接识别. 也可以使用其他名称, 但记得要在命令行的执行指令webpack-dev-server后添加--config FILENAME额外声明配置文件的名称.

现在就可以将package.json中webpack的配置转移:

webpack.config.js

1
2
3
4
5
6
7
8
9
var path = require('path'); // 输出路径需要是绝对路径, 因此要引入Node的path模块来帮助解决这个问题.

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

entry: 值可以是表示单个入口的字符串, 包含多个入口的数组, 也可以是含有多个alias的对象.

path: path.resolve(__dirname, 'dist'): 输出路径必须是绝对路径.

filename: 'bundle.js': bundle.js是习惯用名, 也可以是任何其他名字.

package.json中这样修改:

1
2
3
4
"scripts": {
"build": "webpack-dev-server",
"build-prod": "webpack -p"
}

但是执行npm run build不能正常运行, 因为webpack-dev-server只关注webpack.config.js中”filename”的值, 会忽略前面的路径path的值, 因此还需要在配置文件中声明publicPath:

1
2
3
4
5
6
7
8
module.exports = {
entry: './src/js/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/dist'
}
};

这样配置之后, 使用webpack与webpack-dev-server, 程序就都可以正常运行了.

module-loader

module-loader的作用是转换代码并确保项目中的文件正确加载. 下面以css-loader和style-loader为例简单说明loader的作用.

css-loader & style-loader

使用webpack, 我们可以利用css-loader和style-loader为页面添加样式, css-loader的作用是处理import '../css/main.css';, 因为在默认情况下webpack无法理解对于css文件的引入, style-loader的作用是将引入的css样式以内联样式的形式添加到HTML中.

1.首先npm install --save-dev css-loader style-loader

2.在webpack.config.js中加入module-loader:

1
2
3
4
5
6
7
8
9
10
11
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}

上述代码的意思是, 对于扩展名为css的文件, 使用’style-loader’和’css-loader’.

loader的顺序很重要, 如果把css-loader放在style-loader之前, 样式就无法正常渲染, 因为webpack的执行loader的顺序是从后往前, 因此css-loader应该在style-loader之后.

3.添加正确loader之后的webpack.config.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var path = require('path');

module.exports = {
entry: './src/js/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/dist'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
};

4.同时在app.js中引入css文件:

1
2
import '../css/main.css';
import '../css/input-elements.css';

plugin(插件)

module-loader和plugin的作用看似很相似, 其实不然, 在上面的例子中, module-loader作用于每一个css文件, 但是plugin的作用范围只有bundle.js, 确切地说, 作用于bundle.js产生之前.

一个典型的插件是压缩插件, 尽管我们可以在npm scripts中对webpack的声明加入-p来执行压缩, 但是如果想要对压缩的规则进行进一步配置, 就需要用到插件.

webpack.config.js中加入

1
var webpack = require('webpack'); // 顶部
1
2
3
4
5
6
// 与module同一层级:
plugins: [
new webpack.optimize.UglifyJsPlugin({
// ...
})
]

加入上述代码之后再执行npm run build, bundle.js与之前的执行生成的bundle.js相比文件体积就小了很多.


参考