webpack2進階之多文件,DLL,以及webpack-merge

本須要對webpack已有必定的瞭解,若是你沒接觸過webpack或者剛剛接觸webpack,能夠考慮先看一下個人這篇教程。




1.打包多文件

以前,當須要打包多個而文件時,我是這麼寫的:javascript

module.exports={
  entry:{
    "page/main/main":'./src/js/index.js',
    "page/car/car":"./src/js/car.js",
    "page/goods/goods":"./src/js/goods.js",
  },
  output:{
    filename:"[name].[hash].js",
    path:path.resolve(__dirname,'dist')
  },
    plugins:[
      new webpack.HotModuleReplacementPlugin(),
      new htmlWebpackPlugin({
        title:"首頁",
        template:'./src/index.html',
        filename:"index.html",
        chunks:["page/main/main"]
      }),
      new htmlWebpackPlugin({
        title:"購物車",
        template:'./src/index.html',
        filename:"car.html",
        chunks:["page/car/car"]
      }),
      new htmlWebpackPlugin({
        title:"商品",
        template:'./src/index.html',
        filename:"goods.html",
        chunks:["page/goods/goods"]
      })
      ]

能夠發現,咱們在entry中手動引入了多個文件; 在plugins中,咱們又手動的屢次new htmlWebpackPlugin()。css

雖然可以正常的運行,然而存在不少限制。html

  • 首先:存在大量重複的代碼。如今只有3個頁面,假如現有10個頁面,那麼你就得手動的new10次,在enrty中輸入10個入口。vue

  • 其次:當增長新的頁面時,又得過來webpack的配置裏面手動的再加入到入口文件中。java

明顯的,對於這些重複的並且長得很像的,若是能自動獲取到須要配置的文件,而且在一個循環裏面調用,那就方便多了。node

使用node.js的golb模塊來獲取文件
//引入glob
var glob= require('glob');

//同步讀取src目錄下全部的html文件
var files = glob.sync('./src/*.html');
var entry={};
var plugins=[];

//循環將文件
files.forEach(function(item,i){
    //item相似:./src/index.html

    var htmlName=item.slice(item.lastIndexOf("/")+1);
    //最後生成的文件名只須要最後面的名字index.html
    
    var name=htmlName.split(".")[0];

    //添加到entry入口,並制定生成文件的目錄
    entry["page/"+name+"/"+name]='./src/js/'+name+'.js'

    //生成htmlWebpackPlugin實例
    plugins.push(
        new htmlWebpackPlugin({
            template:item,
            filename:htmlName,
            chunks:["page/"+name+"/"+name]
        })
    )
});

module.exports={
    entry:entry,
    output:{
        filename:"[name].[chunkhash].js",
        path:path.resolve(__dirname,'dist'),
  },
 

  module:{
    rules:[
          {
              test: /\.js$/,
              exclude: /node_modules/,
              use: {
                loader: 'babel-loader'          
            }
        },  
    ]
  },
  plugins:plugins
}

能夠發現,使用glob.sync來讀取文件並進行循環操做,本來須要手動操做的部分,循環已經幫咱們處理好了。本來須要不少new new htmlWebpackPlugin()已經再也不存在,並且即便後續須要添加新的頁面,也不須要咱們手動去添加,glob.sync會本身去讀取全部的*.html文件,接着循環會幫咱們處理。jquery

這裏須要注意的地方就是,index.html對應的js文件必須爲index.js,ceshi.html文件對應的文件必須爲ceshi.js。至於js裏面須要引入其餘庫,或者本身寫的工具函數,哪一個頁面須要,只需引入便可,webpack會本身處理好。webpack

2.使用DLL提取公共庫



當頁面存在引用相同的庫時,最好仍是將這些庫文件提取到單獨的文件,頁面只保留業務邏輯的js代碼。ios

爲了提取文件,有2中處理方案:
  • 使用CommonsChunkPlugin來提取

在上面的代碼上增長:(如下這部分代碼只在使用CommonsChunkPlugin時須要)

entry.vendor=[
     //舉例以下:
     "vue","vuex","axios","jquery","vue-router","moment","lodash"
  ];

  plugins=[   
     new webpack.optimize.CommonsChunkPlugin({
         name:["vendor","manifest"]
       })
  ]

  //修改循環中的chunks, 增長vendor以及manifest:
  files.forEach(function(item,i){
      plugins.push(
          new htmlWebpackPlugin({
              template:item,
              filename:htmlName,
              chunks:["page/"+name+"/"+name,"vendor","mainfest"]
          })
      )
  });

再執行webpack,能夠發現公共的庫已經被提取到單獨的vendor文件。web

  • 使用DLL

對於CommonsChunkPlugin,webpack 每次打包實際仍是須要去處理這些第三方庫,只是打包完以後,能把第三方庫和咱們本身的代碼分開。

DLLPlugin 則是能把第三方代碼徹底分離開,即每次只打包項目自身的代碼。

這裏我使用的是autodll-webpack-plugin。

//安裝模塊
npm install --save-dev autodll-webpack-plugin

//引入模塊
var AutoDllPlugin = require('autodll-webpack-plugin');

在plugins中添加插件:(須要放在循環以前,防止數組被從新賦值)
var plugins=[
  new AutoDllPlugin({
        //文件名
        filename: '[name].[hash].js', 

        //打包後的文件路徑
        path: './page/common/',

        //是否將生成的Js文件注入到html文件中
        inject:true,

        //須要分離的庫
        entry: {
          vendor: [
            "vue","vuex","axios","jquery","vue-router","moment","lodash","vue-touch","vue-lazyload"
          ]
        },

        //壓縮代碼(注意這裏是壓縮分離出來的庫文件代碼,跟外面的要區分開來,若是外面的須要壓縮,外面的plugins中也須要new一個壓縮實例)
        plugins: [
          new webpack.optimize.UglifyJsPlugin()
        ]
      })
]

執行webpack命令,能夠發現公共的庫文件也被打包到單獨的文件了。

autodll-webpack-plugin在內存中緩存了文件,因此當你第二此執行webpack命令進行打包時,能夠明顯發現打包時間少了不少。

CommonsChunkPlugin每次都所有從新打包再進行分離,因此當須要屢次修改文件時,autodll-webpack-plugin能夠明顯下降打包的時間,尤爲是依賴不少外部庫的時候。

3.使用webpack-merge區分生成環境和開發環境:


不少時候,咱們都須要針對不一樣的環境進行不用的操做。

好比在生成環境下分離css到單獨文件:
var extractSass = new ExtractTextPlugin({
    filename: "[name].[contenthash].css",
    disable: process.env.NODE_ENV === "development"
});
在生成環境下要壓縮代碼:

new UglifyJSPlugin();


在開發環境下使用代理
devServer:{
   proxy: {
      'api': {
          target: 'http://api.douban.com/v2/movie/',
          secure: false,
          changeOrigin: true
      }
  }

一般會用process.env.NODE_ENV === "development",而且在package.json中設置環境變量來進行判斷,不過當文件大了或者頁面須要判斷的地方多了以後,配置文件就會充斥着大量三元表達式

能夠考慮用webpack-merge將配置文件拆分爲3個文件,一個是webpack.common.js,即不論是生產環境仍是開發環境都會用到的部分,以及webpack.product.js和webpack.dev.js, 而且使用webpack-merge來合併對象。

common.js

//webpack.common.js
 var path = require('path');
 var HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
     entry: {
         app: './src/index.js'
     },
     output: {
         filename: '[name].bundle.js',
         path: path.resolve(__dirname, 'dist')
     },
     module: {
        rules:[
            {
                 test: /\.js$/,
                 exclude: /node_modules/,
                 use: {
                     loader: 'babel-loader'
                 }
            },
        ]           
     },
    plugins: [
         new HtmlWebpackPlugin({
             title: 'test'
         })
     ],
 }

dev.js

//開發環境webpack.dev.js
var merge = require('webpack-merge');
var common = require('./webpack.common.js');

module.exports = merge(common, {
  module:{
     rules:[
       {
           test: /\.css$/,
           use:["style-loader","css-loader"]
       }
   ]      
 },
  devtool: 'inline-source-map',
  devServer:{
       open:true,  
       hot: true, 
       proxy: {
          '/api/': {
              target: 'http://baidu.com',
              secure: false,
              changeOrigin: true
          }
      }      
    },
})

product.js

//生產環境webpack.product.js
var merge = require('webpack-merge');
var UglifyJSPlugin = require('uglifyjs-webpack-plugin');
var common = require('./webpack.common.js');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var cleanPlugin = require("clean-webpack-plugin");
var extractSass = new ExtractTextPlugin({
    filename: "[name].[contenthash].css",
});

module.exports = merge(common, {
    module: {
        rules: [{
            test: /\.css$/,
            use: extractSass.extract({
                use: [{
                    loader: "css-loader"
                }, ],
                fallback: "style-loader"
            })
        }]

    },
    devtool: 'source-map',
    plugins: [
        new cleanPlugin(["dist"]),
        new UglifyJSPlugin(),
        extractSass,
    ]
});
在packjson中修改webpack默認配置文件
"scripts": {
    "dev": "webpack-dev-server --config webpack.dev.js",
    "build": "webpack --config webpack.product.js"
}

經過npm run dev以及npm run build來執行對應的操做。

以上只是一個簡單的示例,並非必定須要拆分紅3個文件,若是你的配置足夠簡單,寫成一個webpack.config.js足以。可是,假如你的項目足夠龐大,最好仍是拆開來寫,能夠參考vue-cli的腳手架的配置。

相關文章
相關標籤/搜索