Webpack

Author Avatar
A Man Has No Name 3月 20, 2017
  • 在其它设备中阅读本文章

简单介绍一个工具而已

上图

是什么

Webpack 是一个JS模块化打包工具。

需要加工哪些文件

Webpack会为当前应用创建一个完整的依赖关系图。依赖解析的入口文件被称为入口点。这个文件会告诉webpack怎么去管理需要依赖的库文件,并且怎么去打包他们。
在webpack中,我们在webpack.config.js中做配置。
webpack.config.js

1
2
3
4
5
module.exports = {
entry: {
'./app.js'
}
};

如果我们有多个入口文件,如果我们想把入口文件,和vendors文件分开呢

用法: entry: string|Array
webpack.config.js

1
2
3
4
5
6
const config = {
entry: {
app: './app.js',
vendors: './vendors.js'
}
};

以上,是说把app.js和vendor.js分别独立的所有依赖都处理完成。

多页应用

1
2
3
4
5
6
7
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};

加工之后放哪

当把所有的依赖都妥善处置好之后,需要配置把这个处理之后的文件放哪。
webpack.config.js

1
2
3
4
5
6
7
8
9
const path = require('path');
module.exports = {
entry: './app.js'
output: {
path: path.reslove(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};

output 需要最基本的需要两个配置

  • output.filename, 编译之后的文件名,比如 main.js || bundle.js || index.js。切记不要写加文件路径,比如../test/main.js

    • 如果只有一个入口文件,

      1
      2
      3
      4
      5
      6
      7
      8
      {
      entry: './src/app.js',
      output: {
      filename: 'bundle.js',
      path: __dirname + '/build'
      }
      }
      // writes to disk: ./build/bundle.js
    • 如果有多个入口文件, 那么你就需要把文件名配置成参数形式:

      • [name], 加上名字
      • [hash], 加上hash串
      • [chunkhash], [chunkHash:5], 表示保留五位hash,其他同上
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        {
        entry: {
        app: './src/app.js',
        search: './src/search.js'
        },
        output: {
        filename: '[name].[id].js',//只要你喜欢,可以拼成[name].[hash].[chunkhash].js
        path: __dirname + '/build'
        }
        }
        // writes to disk: ./build/app.js, ./build/search.js
  • output.path, 一个 绝对路径 地址,

    • 如果js使用了cdn的地址,那么
      1
      2
      3
      4
      5
      6
      output: {
      path: "/home/proj/cdn/assets/[hash]",
      publicPath: "http://cdn.example.com/assets/[hash]/"
      }
      // 如果一开始你不知大publicPath, 那么这个为止可以为空,然后在入口文件中写入
      __webpack_public_path__ = "http://cdn.example.com/assets/[hash]/"

    其他徐昂想配置有

  • output.chunkFilename, 按需加载的时候,如果这个文件并没有写入entry中,那么它处理的时候起名方式 例子
    • [id], 可以用ID拼
    • [name], 同上
    • [hash], 同上
    • [chunkhash], 同上
  • output.crossOriginLoading, 设置跨域加载块
    • false, 默认,禁止跨域加载。
    • anonymous, 开启允许跨域加载。
    • use-credentials, 标志启用验证,cookie,SSL,HTTP验证等
  • output.hotUpdateChunkFilename, 配置热更新chunk文件名, 它包含在output.path里面,
    • [id]
    • [hash]
    • 默认起名: [id].[hash].hot-update.js
  • output.hotUpdateFunction, 一个异步加载人更新chunk方法,JSONP的方法, 默认是: webpackHotUpdate
  • output.hotUpdateMainFilename, 热更新主文件名, 它包含在output.path里面,默认是: [hash].hot-update.json
  • output.jsonpFunction, 用于异步加载模块的时候使用JSONP的方法名,默认是:webpackJsonp, 注意两点
    • 起一个短一些的名字,能减少网络传输
    • 如果是单页面程序,那么注意不要命名冲突
  • output.library, 如果设置了的话名字的话,也就是给库起个名字,比如jquery,那么它可以导出成一个library库,并且可以单独发布它。
  • output.libraryTarget, 库的类型
    • var, 默认的,以一个普通变量的形式调用, var Library = xxx
    • this, 设置一个属性,this: this[“Library”] = xxx
    • commonjs, exports: exports[“Library”] = xxx
    • commonjs2, module.exports: module.exports = xxx
    • amd, 没用过,欢迎补充
    • umd, 没用过,欢迎补充
  • output.sourceMapFilename, 可以自定义js的sourceMap文件名,默认是是”[file].map”
    • [file]
    • [id]
    • [hash]

那么,除了JS其他文件类型怎么办

Webpack本身只能处理JS的内容,那么如果需要处理css,html,scss,jpg,png等怎么办。这就需要插件,我们加它loader。
不同的loaders处理各自的文件,然后会把各自要处理的文件,放到依赖关系中。
总体来说,它会做两件事:

  1. 确定哪些文件要被哪些loader处理
  2. 处理这些文件,然后把这些文件放到依赖关系中。

注意:
-loader其实是可以省略不写的,也就是说css-loader可以写成css
多个loader之间用“!”连接起来,比如style-loader!css-loader

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const path = require('path');
const config = {
entry: './app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{test: /\.(js|jsx)$/, use: 'babel-loader'} // 把js,jsx文件,扔到babel-loader中处理
]
}
};
module.exports = config;

Loaders

  1. 如果我们需要过滤css文件,那么我们首先要找到css的loader

    1
    npm install --save-dev css-loader
  2. 我们在webpack.config.js中配置css过滤规则

    1
    2
    3
    4
    5
    6
    7
    module.exports = {
    module: {
    rules: [
    {test: /\.css$/, use: 'css-loader'}
    ]
    }
    };
  3. 还有一种更复杂的写法, 用来优雅的处理不同的loader

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    module: {
    rules: [
    {
    test: /\.css$/,
    use: [
    { loader: 'style-loader'},
    {
    loader: 'css-loader',
    options: {
    modules: true
    }
    }
    ]
    }
    ]
    }
  4. 命令行模式调用loader

    1
    $ webpack --module-bind css-loader --module-bind 'css=style-loader!css-loader'

Resolve配置,不建议修改

本模块用来,修改加载模块的方式。一般情况下,不需要你对Webpack的模块加载进行干预,因为它已经很智能了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module.exports = {
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
......

resolve.alias

  1. 给你的要导入的模块起一个简称,比如 reslove(‘src’) 路径变成 ‘@’ 符号, 那么你需要执行你要引入src中的文件
1
import Hello from '@/components/Hello'
  1. ‘$’, 符号,一般放在单词后面,比如’vue$’, 标示精确匹配,比如
    1
    2
    3
    alias: {
    'vue$': 'vue/dist/vue.esm.js',
    }

那么,当你引入的时候

1
2
3
4
5
// 正确的✅
import Test1 from 'vue'
//错误的❌
import Test2 from 'vue/te'

从官网抄的

alias: import “xyz” import “xyz/file.js”
{} /abc/node_modules/xyz/index.js /abc/node_modules/xyz/file.js
{ xyz: “/abs/path/to/file.js” } /abs/path/to/file.js error
{ xyz$: “/abs/path/to/file.js” } /abs/path/to/file.js /abc/node_modules/xyz/file.js
{ xyz: “./dir/file.js” } /abc/dir/file.js error
{ xyz$: “./dir/file.js” } /abc/dir/file.js /abc/node_modules/xyz/file.js
{ xyz: “/some/dir” } /some/dir/index.js /some/dir/file.js

resolve.extensions,没事别修改它!

1
2
3
4
extensions: [".js", ".json"]
//可能是./extt.json, 也可能是./ext.js
import test from './extt'

默认系统会在寻找 .js. .json的文件

如果你覆盖的了这个默认的文件类型,就不知道会出什么事了

其他

当然,webpack一定是支持插件的,loaders可以处理基础文件,如果有些自一定的处理,比如压缩文件,加入混淆字符串等,就需要plugins。
使用的时候,只要require对应的plugin, 然后new 一个实例姐可以了。这样,更神奇的是,你可以为了不同的目的,使用多次同一个plugin。

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
const config = {
entry: './app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{test: /\.(js|jsx)$/, use: 'babel-loader'}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(), // 混淆压缩文件
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;

更多plugins,请访问 点我

一个复杂的配置信息例子

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
27
28
29
30
31
32
33
34
35
36
37
38
var path = require('path');
var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var baseConfig = {
target: 'async-node',
entry: {
entry: './entry.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'inline',
filename: 'inline.js',
minChunks: Infinity
}),
new webpack.optimize.AggressiveSplittingPlugin({
minSize: 5000,
maxSize: 10000
}),
]
};
let targets = ['web', 'webworker', 'node', 'async-node', 'node-webkit', 'electron-main'].map((target) => {
let base = webpackMerge(baseConfig, {
target: target,
output: {
path: path.resolve(__dirname, 'dist/' + target),
filename: '[name].' + target + '.js'
}
});
return base;
});
module.exports = targets;

JS语法规则

1
2
3
4
5
6
7
8
9
10
$ babel-preset-es2015
# react转码规则
$ babel-preset-react
# ES7不同阶段
$ babel-preset-stage-0
$ babel-preset-stage-1
$ babel-preset-stage-2
$ babel-preset-stage-3

VUE-LOADER

是什么

过滤编译vuejs为普通JS的模块