1.webpack配置了解

 webpack的配置文件是一个nodejs的module,使用CommonJS风格来编写的,比如如下:

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

module.exports = {
  entry: './index',
  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js'
  }
}

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

webpack的配置文件可以随便命名,默认为 webpack.config.js,因此在项目的根目录下,直接运行 webpack就可以进行打包,但是也可以对webpack命名为其他的名字,比如把它放入 build/webpack.dev.js ,代码目录结构如下:

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

### 目录结构如下:
demo                                        # 工程名|   |--- dist                               # 打包后生成的目录文件             
|   |--- node_modules                       # 所有的依赖包|   |--- src                                # 项目的文件包|   |    |--- pages                         # 存放所有页面的文件|   |    |    |--- page1|   |    |    |    |--- index.html          # 第一个页面的html文件|   |    |    |    |--- index.styl          # 第一个页面的css文件|   |    |    |    |--- index.js            # 第一个页面的js文件|   |    |    |--- page2|   |    |    |    |--- index.html          # 第二个页面的html文件|   |    |    |    |--- index.styl          # 第二个页面的css文件|   |    |    |    |--- index.js            # 第二个页面的js文件|   |--- build|   |    |--- webpack.base.js               # webpack 基本配置文件|   |    |--- webpack.dev.js                # 开发文件|   |    |--- webpack.build.js              # 打包线上文件                               
|   |--- .gitignore  
|   |--- README.md|   |--- package.json

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

因此我们在package.json 配置文件如下:

"scripts": {  "dev": "node build/webpack.dev.js",  "build": "node build/webpack.build.js"}

进入项目的根目录后,运行 npm run dev 即可进行打包。

1.1) 入口文件配置 entry参数

   entry入口文件可以是字符串的单入口文件,也可以是数组的多入口文件,但是我们最常见的是一个对象的方式来组织入口文件。因此object中的key在webpack里相当于入口的name,可以用来生成文件的路径,也可以使用来为此入口唯一的标识。
比如如下:

entry: {  'page1': path.resolve(__dirname, '../src/pages/page1'),  'page2': path.resolve(__dirname, '../src/pages/page2')
}

假如页面上有多个入口的话,这样一个个写比较麻烦,因此可以写一个函数如下:

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

/*
 获取项目中多个入口文件*/function getEntries(paths) {  // node 中同步获取文件列表
  var files = glob.sync(paths),
    entries = {};

  files.forEach(function(filepath) {    var toArray = filepath.split('/');    var filename = toArray[toArray.length - 2];
    entries[filename] = filepath;
  });  return entries;
}var entries = getEntries('./src/pages/*/index.js');
Object.keys(entries).forEach(function(name) {
  entry[name] = entries[name]
});

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

1.2) 输出文件:out参数

output参数是告诉webpack以什么方式来生成/输出文件,output有几个常用的参数如:path, publicPath, filename, chunkFilename, 如下代码:

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

output: {
  path: path.resolve(__dirname, '../dist'),
  publicPath: '/assets/',   // 供插件在生产模式下更新内嵌到css、html文件里的相对路径url值
  filename: 'static/js/[name].js',
  chunkFilename: '[id].bundle.js',
}

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

1.3) path参数

   path参数表示生成文件的根目录,需要传入一个绝对路径,如:path.resolve(__dirname, '../dist'),会解析成 /项目的根目录下/dist文件, path参数和filename参数会共同组成入口文件的完整路径。

1.4) publicPath

该参数表示的是一个URL路径(指向生成文件的根目录),可以用于css/js/images/font文件等资源的路径,可以确保网页正确的加载到这些资源文件。

1.5) publicPath参数 和 path参数的区别:

   path参数是针对本地文件系统的,但是publicPath则针对的是浏览器,它既可以是一个相对路径,比如 '../../dist', 也可以是一个绝对路径,比如:'http://www.xxx.com/', 那么什么时候使用相对路径呢?什么时候使用绝对路径呢?如果是引用本项目下的文件,最好使用相对路径,如果是引用跨项目的文件,需要使用绝对路径。

1.6) filename

filename属性表示的是如何命名生成的入口文件,可以有如下规则:
  1. [name], 指代入口文件的name,也就是上面的entry中的key。
  2. [hash] 指代本次编译的一个hash版本,但是请注意,只要在同一次编译过程中生成的文件,这个[hash]值就是一样的,每一次编译,hash值都是一样,也就是说不存在缓存文件,只要一编译所有的hash
都会改变。
  3. [chunkhash] 指代当前chunk的一个hash版本,也就是说,在每次编译过程中,每一个chunk的hash都是不一样的,如果某个chunk没有发生变化,那么该chunk的hash也不会发生变化,也就是可以理解如果页面的文件没有发生改变,那么chunk的hash也不会发生改变,因此未改变的文件会在缓存中读取。
1.7) chunkFilename

   chunkFilename 参数 与 filename参数类似,都是用来定义生成的命名方式的,只不过,chunkFilename参数指定的是除了入口文件外的chunk。

1.8) module参数中的 rules 配置(其实rules就相当于之前的loaders):

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

module: {
  rules: [
    {
      test: /\.js$/,
      include: [
        path.resolve(__dirname, 'src/pages/**/*.js')
      ],
      exclude: /(node_modules)/,      // 排除node_modules 文件      use: {
        loader: 'babel-loader',
        options: {
          presets: ['es2015'],
          plugins: ['transform-runtime']
        }
      }
    }
  ]
}

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

下面对一些子参数进行说明:
test: test其实是一个使用正则表达式匹配文件的一种方式,比如上面的是,匹配以 .js结尾的文件。
include: 用来表示本rules 配置是针对那些目录/文件,比如上面的代码配置是针对 src/pages/ 下的所有js文件的。
exclude: 是用来排除掉那些文件的,比如上面的是 /(node_modules)/ 的意思是 排除掉 node_modules下的js文件的。
use: 使用到的loader的配置
use 下的 loader: 使用加载器名称。
options: 该参数是为当前loader设置的参数,对于babel也可以单独放在 .babelrc文件中,也就是说该参数可以在项目的根目录不包含.babelrc文件,把.babelrc文件移到该配置项来即可。

回到顶部

2.webpack CommonsChunkPlugin公共代码剥离

    与单页应用相比,多页应用存在多个入口(每个页面即一个入口),每个入口意味着一套完整的js代码(包括业务逻辑和加载第三方库、框架)。然后在每个页面中分别加载该文件即可,

CommonsChunkPlugin: 该插件是一个可选用于建立一个独立文件(chunk), 这个文件包括多个入口的chunk的公共模块,通过将公共模块拆出来,最终合成的文件能够在最开始的时候加载一次,便存到缓存中,供后续使用,优点是:会带来速度的提升,因为浏览器会迅速将公共的代码从缓存中提取出来
,而不是每次访问一个新页面时候,再去加载一个更大的文件。

CommonsChunkPlugin 初始化有哪些参数?
name: 给这个包含公共代码的chunk命名。
filename: 命名打包后生成的js文件。
minChunks 公共代码的判断标准:某个js模块被多少个chunk(入口文件)加载了才算是公共代码。
chunks,表示需要在哪些chunk(配置中entry的每一项)里寻找公共代码进行打包,默认不设置,那么它的提取范围为所有的chunk。

下面是一个简单的CommonsChunkPlugin的实列含义:

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

var commonsChunkPlugin = new webpack.optimize.CommonsChunkPlugin = ({
  name: 'vender',     // 这公共代码的chunk命名为 'vender'
  filename: '[name].bundle.js',  // 生成的文件名为 vender.bundle.js
  minChunks: 2,     // 设定要有2个chunk(即2个页面)加载的js模块才会被纳入公共代码。
  chunks: ['pageA', 'pageB'],  // 只使用这些入口的 chunk})var commonsChunkPlugin = new webpack.optimize.CommonsChunkPlugin = ({
  name: 'vender',     // 这公共代码的chunk命名为 'vender'
  // filename: '[name].bundle.js',  // 生成的文件名为 vender.bundle.js
  minChunks: Infinity,  // 随着入口chunk越来越多,这个配置保证没其他的模块会打包进 公共的chunk})

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

下面是使用对 webpack CommonsChunkPlugin 详解的demo:

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

### 目录结构如下:
demo                                        # 工程名|   |--- dist                               # 打包后生成的目录文件             
|   |--- node_modules                       # 所有的依赖包|   |--- src                                # 项目的文件包|   |    |--- common|   |    |     |---css                      # 公用页面的css文件|   |    |     |---js                       # 公用页面的js文件|   |    |--- libs|   |    |     |--- jquery.js               # 第三方库文件   
|   |    |--- main.js                       # 入口文件|   |--- .gitignore  
|   |--- README.md|   |--- index.html                         # 首页文件|   |--- package.json                      
|   |--- webpack.config.js                  # 配置文件 
|   |--- webpack.production.config.js       # 上线打包配置文件

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

1.1) 未使用 CommonsChunkPlugin 打包情况下
webpack.config.js 代码如下:

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

// 导入路径包const path = require('path'); 
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {    //开启sourceMap便于调试
    devtool: 'eval-source-map', 

    //入口文件,    entry: {
      main: './src/main.js'
    }, 

    output: {      // 输出文件到当前目录下的 build文件夹内
      path: path.resolve(__dirname, 'build'), 
      publicPath: '/assets/', //指定资源文件引用的目录
      filename: 'bundle.js' // 文件名为 bundle.js
      //filename: '[name].js' // 可以打包为多个文件    },
    resolve: {
      extensions: ['*', '.js', '.json'],
    },    // 使用loader模块    module: {        /* 
         * 在webpack2.0版本已经将 module.loaders 改为 module.rules, 当然module.loaders也是支持的。
         * 同时链式loader(用!连接)只适用于module.loader,同时-loader不可省略 
         */
        rules: [
          {
            test: /\.css$/,
            use: [              'style-loader', {
                loader: 'css-loader',
                options: {                  // modules: true // 设置css模块化,详情参考 https://github.com/css-modules/css-modules                }
              }, 
              {
                loader: 'postcss-loader',                // 参考 https://github.com/postcss/postcss-loader                options: {
                  plugins: function() {                    return [
                      require('autoprefixer')
                    ];
                  }
                }
              }]
          }, 
          {
            test: /\.styl(us)?$/,
            use: [                'style-loader', 'css-loader', {
                   loader: "postcss-loader",
                   options: {
                      plugins: function() {                        return [
                          require('autoprefixer')
                        ];
                      }
                    }
                }, 'stylus-loader']
          }, 
          {
            test: /\.js$/,
            loader: 'babel-loader', 
            exclude: /node_modules/ //需要排除的目录          }
        ]
    },    // 配置devServer各种参数    devServer: {        // contentBase: "./",   // 本地服务器所加载的页面所在的目录
        hot: true,              // 配置HMR之后可以选择开启
        historyApiFallback: true, // 不跳转
        inline: true // 实时刷新    },
    plugins: [      new HtmlWebpackPlugin({
          template: './index.html' // 模版文件      }),      new webpack.HotModuleReplacementPlugin(), // 热加载插件    ]
}

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

main.js代码如下:

require('./common/css/style.css');
import './common/css/stylus.styl';
require('./libs/jquery.js');

运行命令 npm run start 可以看到打包后的文件 bundle.js 代码内 包含第三方jquery框架的源码。

1.2)使用CommonsChunkPlugin 
单一入口文件,分文件输出 
webpack.config.js 代码如下:

Android培训,安卓培训,手机开发培训,移动开发培训,云培训培训

// 导入路径包const path = require('path'); 
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");

module.exports = {    //开启sourceMap便于调试
    devtool: 'eval-source-map', 

    //入口文件,    entry: {
      main: './src/main.js'
    }, 

    output: {      // 输出文件到当前目录下的 build文件夹内
      path: path.resolve(__dirname, 'build'), 
      filename: '[name].js' // 可以打包为多个文件    },
    resolve: {
      extensions: ['*', '.js', '.json'],
    },    // 使用loader模块    module: {        /* 
         * 在webpack2.0版本已经将 module.loaders 改为 module.rules, 当然module.loaders也是支持的。
         http://www.cnblogs.com/tugenhua0707/p/7191309.html

网友评论