webpack 入门教程

webpack 是什么, 它自称 MODULE BUNDLER,也就是模块打包器。对于 webpack 来说,所有的文件都可以是模块,都是可以管理、打包处理的。

安装 webpack

和普通的 nodejs 模块一样,我们可以全局安装使其变成全局变量,也可以只在项目中安装。

npm install webpack -g

npm install webpack --save-dev

webpack 配置

webpack 的运行是需要一个配置文件,默认为 webpack.config.js,在项目根目录下。其主要内容为:


var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
    //插件项
    plugins: [new ExtractTextPlugin("[name].css")],

    //页面入口文件配置
    entry: {
        index: './src/js/index.js'
    },

    //入口文件输出配置
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },

    module: {
        //加载器配置
        loaders: [
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract("style-loader", "css-loader")
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                query: {
                    // presets: ['es2015','stage-0']
                }
            },
            {
                test: /\.(png|jpg)$/,
                loader: 'url-loader',
                query: {
                    limit: 8192
                }
            }
        ]
    },

    devServer: {
        // historyApiFallback: true,
        // hot: true,
        inline: true
    },

    //其它解决方案配置
    resolve: {
        // module 查找路径
        // root: 'E:/github/flux-example/src', //绝对路径

        // 可以作为module的文件后缀
        extensions: ['', '.js'],

        // 模块变量别名
        alias: {
            // AppStore : 'js/stores/AppStores.js',
            // ActionType : 'js/actions/ActionType.js',
            // AppAction : 'js/actions/AppAction.js'
        }
    }
};

基本上都有注释,但是有几个重要的配置项需要单独拿出来说明一下。

entry:

这是配置 webpack 的入口文件。简单的说就是,webpack 打包的时候,会从这里定义的文件开始解决依赖,完成打包。入口文件可以是多个文件,entry 的值可以是一个字符串路径,也可以是一个字符串列表,也可以是一个对象。我这里建议大家用对象配置,因为对象的 key 值会作为名称传入 output 中。

output:

这里配置的是 webpack 打包完成的文件输出。path 定义输出路径,fileName 定义 输出文件名。

这里要着重说明一下,fileName 的值虽然是字符串,但是其中可以有变量存在,比如

fileName: '[name].js'

其中的 [name] 就是 entry 中对象的 key 值!如果你没有把 entry 设置成 对象,那么这里的 [name] 值就是main。当然除了 [name] 变量,还有 [id] 和 [contenthash] 这两个变量可以用。

module

这里就是 webpack 的重头戏。在这里我们可以配置对不同文件应用不同的处理方式。

module: {
    //加载器配置
    loaders: [
        {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract("style-loader", "css-loader")
        },
        {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            query: {
                // presets: ['es2015','stage-0']
            }
        },
        {
            test: /\.(png|jpg)$/,
            loader: 'url-loader',
            query: {
                limit: 8192
            }
        }
    ]
},

test 是用来匹配文件,值为正则表达式;loader 是对匹配的文件应用的处理器,比如对 css 文件应用 css-loader 和 style-loader 处理器;query 是用来传递参数到处理器,也可以直接加载 loader 后面,类似 url 传参;exclude 为排除选项,值也是正则表达式,用来排除不需要处理的文件。

devServer

这里主要是配置和 webpack-dev-server 相关的参数,webpack 也提供一个简易的本地服务器,可以通过链接直接访问 index.html 文件。

同时,webpack 还支持自动刷新,有两种模式 iframe 和 inline,两者的区别在于:

  1. iframe 模式:我们不访问 http://localhost:8080,而是访问 http://localhost:8080/webpack-dev-server/index.html
  2. inline 模式:在命令行中指定该模式,webpack-dev-server --inline。这样 http://localhost:8080/index.html 页面就会在 js 文件变化后自动刷新了。

 运行 webpack

webpack 在运行时可以添加参数,其中有一下几个参数是我们用到的最多的。

$ webpack --config XXX.js   //使用另一份配置文件(比如webpack.config2.js)来打包

$ webpack --watch   //监听变动并自动打包

$ webpack -p    //压缩混淆脚本,这个非常非常重要!

$ webpack -d    //生成map映射文件,告知哪些模块被最终打包到哪里了

模块引入

1、html 部分

在 html 中引用相应的资源的方式有两种,一种直接引用打包完成后的资源,但缺点是不能自动刷新了;另外一种就是只引用 output 资源名称,然后运行 webpack-dev-server 自动刷新,它会自动替换资源,其中 css 文件也不会要引入,webpack会自动添加到 head 中。

2、JS 部分

在 js 中引用别的资源的方式为 require,其中不论类型,css、image 都可以当成模块引入。

其他

一、shimming

在 AMD/CMD 中,我们需要对不符合规范的模块(比如一些直接返回全局变量的插件)进行 shim 处理,这时候我们需要使用 exports-loader 来帮忙:

{
    test: require.resolve("./src/js/tool/swipe.js"),
    loader: "exports?swipe"
}

之后在脚本中需要引用该模块的时候,这么简单地来使用就可以了:

require('./tool/swipe.js');
swipe(); 

二、自定义公共模块提取

在文章开始我们使用了 CommonsChunkPlugin 插件来提取多个页面之间的公共模块,并将该模块打包为 common.js 。

但有时候我们希望能更加个性化一些,我们可以这样配置:

var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
    entry: {
        p1: "./page1",
        p2: "./page2",
        p3: "./page3",
        ap1: "./admin/page1",
        ap2: "./admin/page2"
    },
    output: {
        filename: "[name].js"
    },
    plugins: [
        new CommonsChunkPlugin("admin-commons.js", ["ap1", "ap2"]),
        new CommonsChunkPlugin("commons.js", ["p1", "p2", "admin-commons.js"])
    ]
};
// <script>s required:
// page1.html: commons.js, p1.js
// page2.html: commons.js, p2.js
// page3.html: p3.js
// admin-page1.html: commons.js, admin-commons.js, ap1.js
// admin-page2.html: commons.js, admin-commons.js, ap2.js

三、独立打包样式文件

有时候可能希望项目的样式能不要被打包到脚本中,而是独立出来作为 css,然后在页面中以 <link> 标签引入。这时候我们需要 extract-text-webpack-plugin 来帮忙:

var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
  module: {
    loaders: [
      { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
    ]
  },
  plugins: [
    new ExtractTextPlugin("styles.css")
  ]
}

四、使用CDN/远程文件

有时候我们希望某些模块走CDN并以<script>的形式挂载到页面上来加载,但又希望能在 webpack 的模块中使用上。

这时候我们可以在配置文件里使用 externals 属性来帮忙:

{
    externals: {
        // require("jquery") 是引用自外部模块的
        // 对应全局变量 jQuery
        "jquery": "jQuery"
    }
}

需要留意的是,得确保 CDN 文件必须在 webpack 打包文件引入之前先引入。

我们倒也可以使用 script.js 在脚本中来加载我们的模块:

var $script = require("scriptjs");
$script("//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js", function() {
  $('body').html('It works!')
});

最后提供一份 webpack 模板 webpack-example