關於webpack的使用

關於webpackjavascript

webpakc的是模塊打包器.而不是任務執行器。css

它作的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),並將其轉換和打包爲合適的格式供瀏覽器使用。
webpack也提供了便捷的打包流程,項目構建,插件管理等等.
爲更好的構建項目,從開發到生產都一一提供瞭解決方案.
Vue官方也推薦使用的vue-loader也是基於webpack的.html

WebPack和Grunt以及Gulp相比有什麼特性

Gulp/Grunt是一種可以優化前端的開發流程的工具,而WebPack是一種模塊化的解決方案,不過Webpack的優勢使得Webpack在不少場景下能夠替代Gulp/Grunt類的工具。前端

Grunt和Gulp的工做方式是:在一個配置文件中,指明對某些文件進行相似編譯,組合,壓縮等任務的具體步驟,工具以後能夠自動替你完成這些任務。vue

Webpack的工做方式是:把你的項目當作一個總體,經過一個給定的主文件(如:index.js),Webpack將從這個文件開始找到你的項目的全部依賴文件,使用loaders處理它們,最後打包爲一個(或多個)瀏覽器可識別的JavaScript文件。java

Webpack的處理速度更快更直接,能打包更多不一樣類型的文件。node

一個常見的webpack配置文件react


webpack.config.jswebpack

 

const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');
  const webpack = require('webpack');

  module.exports = {
    entry: {//惟一入口文件路徑
      app: './src/index.js'
    },
    output: {
      //publicPath:XXX 能夠資金定義路徑,build後輸出的內容將會放入到這個路徑當中
      filename: '[name]-[hash].js', //打包後輸出文件的文件名,注意name用方括號括起來,name的值對應的爲entry的key值,這樣爲了區分多個文件 
      path: path.resolve(__dirname, 'dist')//打包後的文件存放的地方(__dirname指向當前執行腳本所在的目錄)
    },
    devtool: 'eval-source-map',//Source Maps提供了一種對應編譯文件和源文件的方法,使得編譯後的代碼可讀性更高,也更容易調試,強調你只應該開發階段使用它
    devServer: {//本地開發服務器,瀏覽器監聽你的代碼的修改,並自動刷新顯示修改後的結果
      contentBase: './dist',//本地服務器所加載的頁面所在的目錄
      historyApiFallback: true, //不跳轉,全部的跳轉將指向index.html
      inline: true,//實時刷新
      hot: true
    },
    module: {//Loaders須要單獨安裝而且須要在webpack.config.js中的modules關鍵字下進行配置
     rules: [
       {
         test: /\.css$/,//一個用以匹配loaders所處理文件的拓展名的正則表達式(必須)
         use: [
             {
                loader: "style-loader"
            }, {
                loader: "css-loader",
                options: {
                    modules: true, //經過CSS模塊,全部的類名,動畫名默認都只做用於當前模塊。 指定啓用css modules,把CSS的類名傳遞到組件的代碼中,這樣作有效避免了全局污染
                    localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的類名格式
                }
         ]//css-loader使你可以使用相似@import 和 url(...)的方法實現 require()的功能,style-loader插件使對於CSS文件進行實時渲染到頁面中,兩者組合在一塊兒使你可以把樣式表嵌入webpack打包後的JS文件中。
       },
       {
         test: /(\.jsx|\.js)$/,
         use: {
            loader: "babel-loader",//loader的名稱(必須)
            options: {//爲loaders提供額外的設置選項(可選)
                        presets: [
                            "env", "react"//解析Es6的babel-env-preset包和解析JSX的babel-preset-react包
                        ]
                    }
         },
         exclude: /node_modules/  //include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)(可選);
        },
        {
         test: /\.css$/,
         use: ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: [{
                loader: "css-loader",
                options: {
                    modules: true,
                    localIdentName: '[name]__[local]--[hash:base64:5]'
                }
            },
            {
                loader: "postcss-loader"//自動添加適應不一樣瀏覽器的css前綴
            }],
         })
        }
       
     ]
    },
    plugins: [
      new CleanWebpackPlugin(['dist']),//清除dist目錄
      new HtmlWebpackPlugin({ //依據一個簡單的index.html模板,生成一個自動引用你打包後的JS文件的新index.html。
        title: 'Hot Module Replacement'
      }),
      new webpack.NamedModulesPlugin(),//添加該插件更容易觀察依賴文件被更新
      new webpack.HotModuleReplacementPlugin(),//動態替換文件,熱加載插件
      new webpack.BannerPlugin('版權全部,翻版必究'),//版本申請插件
      new webpack.optimize.CommonsChunkPlugin({
        name: 'common' // Specify the common bundle's name.
      }),
      new webpack.HashedModuleIdsPlugin(),//
      new webpack.optimize.OccurrenceOrderPlugin(),//爲組件分配ID,經過這個插件webpack能夠分析和優先考慮使用最多的模塊,併爲它們分配最小的ID
      new webpack.optimize.UglifyJsPlugin(),//壓縮JS代碼
      new ExtractTextPlugin("style.css")//分離CSS和JS文件
    ],
    
  };

 

 

package.jsones6

{
  "name": "webpack demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack",
    "server": "webpack-dev-server --open",
    "build": "NODE_ENV=production webpack --config ./webpack.prod.js --progress"
  },
  "author": "",
  "license": "ISC","dependencies": {

    "swiper": "^4.0.7",
    "vue": "^2.5.2",
    "vue-router": "^2.8.1",
    "element-ui": "2.2.1",

"react": "^15.6.1",
     "react-dom": "^15.6.1"
  }
}

 

使用webpack

1. 安裝

全局安裝:

//全局安裝
npm install -g webpack

局部安裝:

//局部安裝
npm install --save-dev webpack

2.工程結構

能夠根據項目的實際的狀況設置目錄。
通常狀況下能夠設置爲源碼目錄,生產目錄。

目錄結構以下:

 

3. 寫一個webpack.config.js配置文件,首先是入口文件路徑(entry)和打包後文件的存放路徑(output)。

module.exports = {
  entry:  __dirname + "/src/main.js",//已屢次說起的惟一入口文件
  output: {
    path: __dirname + "/dist",//打包後的文件存放的地方
    filename: "bundle.js"//打包後輸出文件的文件名
}

4. 對npm進行配置後能夠在命令行中使用簡單的npm start命令來執行打包任務。在package.json中對scripts對象進行相關設置便可,package.json中的script會按照必定順序尋找命令對應位置,具體設置方法以下:

{
  "name": "webpack-sample-project",
  "version": "1.0.0",
  "description": "Sample webpack project",
  "scripts": {
    "start": "webpack" 
  },
  "author": "zhang",
  "license": "ISC",
  "devDependencies": {
    "webpack": "3.10.0"
  }
}

注意:

npm的start命令是一個特殊的腳本名稱,其特殊性表如今,在命令行中使用npm start就能夠執行其對於的命令。若是對應的此腳本名稱不是start,想要在命令行中運行時,須要這樣用npm run {script name},npm run build

5. 開發工具

webpack 提供了強大的開發工具

webpack-server 提供了訪問頁面的服務

webpack-watch 提供了觀察文件的變化 

1> source maps

開發老是離不開調試,方便的調試能極大的提升開發效率,不過有時候經過打包後的文件,你是不容易找到出錯了的地方,對應的你寫的代碼的位置的。而webpack能夠在打包時爲咱們生成source maps,這爲咱們提供了一種對應編譯文件和源文件的方法,使得編譯後的代碼可讀性更高,也更容易調試。

webpack的配置文件中配置source maps,須要配置devtool。

對小到中型的項目中,eval-source-map是一個很好的選項,再次強調,你只應該開發階段使用它。

module.exports = {
  devtool: 'eval-source-map',//source maps,便於調試
  entry:  __dirname + "/src/main.js",
  output: {
    path: __dirname + "/dist",
    filename: "bundle.js"
  }
}

2>使用webpack構建本地服務器

爲webpack打包生成的文件提供web服務,讓你的瀏覽器監聽你的代碼的修改,並自動刷新顯示修改後的結果,其實Webpack提供一個可選的本地開發服務器,這個本地服務器基於node.js構建,能夠實現你想要的這些功能,不過它是一個單獨的組件,在webpack中進行配置以前須要單獨安裝它做爲項目依賴。

npm install --save-dev webpack-dev-server

webpack.config.js配置文件以下:

module.exports = {
  devtool: 'eval-source-map',

  entry:  __dirname + "/src/main.js",
  output: {
    path: __dirname + "/dist",
    filename: "bundle.js"
  },

  devServer: {
    contentBase: "./dist",//設置本地服務器訪問的基本目錄
    historyApiFallback: true,//不跳轉
    inline: true//實時刷新
  } 
}

package.json中的scripts對象中添加以下命令,用以開啓本地服務器:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack",
    "server": "webpack-dev-server --open"
  },

在終端中輸入npm run server,便可在本地的8080端口查看結果

6. Loaders

Loaderswebpack提供的最激動人心的功能之一。經過使用不一樣的 loaderwebpack有能力調用外部的腳本或工具,實現對不一樣格式的文件的處理,好比說分析轉換scss爲css,或者把下一代的JS文件(ES6,ES7)轉換爲現代瀏覽器兼容的JS文件,對React的開發而言,合適的Loaders能夠把React的中用到的JSX文件轉換爲JS文件。
 
Loaders須要單獨安裝而且須要在webpack.config.js中的modules關鍵字下進行配置。
 
Loaders的配置包括如下幾方面:
  • test:一個用以匹配loaders所處理文件的拓展名的正則表達式(必須)
  • use: 進行轉換時,應該使用哪一個loader
  • loader:loader的名稱(必須)
  • include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)(可選);
  • query:爲loaders提供額外的設置選項(可選)
1> css
webpack提供兩個工具處理樣式表, css-loader和  style-loader,兩者處理的任務不一樣。
css-loader使你可以使用相似 @import和  url(...)的方法實現  require()的功能;
style-loader將全部的計算後的樣式加入頁面中;
兩者組合在一塊兒使你可以把樣式表嵌入webpack打包後的JS文件中。

安裝style-oader、css-loader,loader的做用就是將文件進行處理(編譯,壓縮)

npm install --save-dev style-loader css-loader
module.exports =     
{
    module: {
      rules: [
        {
          test: /\.css$/, //指定匹配文件,使用style-loader,css-loader
          use: [
            'style-loader',
            'css-loader'
          ]//引入的順序相當重要,不可改變
      }]
     }
}

css預處理器

Sass 和 Less 之類的預處理器是對原生CSS的拓展,它們容許你使用相似於variablesnestingmixinsinheritance等不存在於CSS中的特性來寫CSS,CSS預處理器能夠這些特殊類型的語句轉化爲瀏覽器可識別的CSS語句。

如下是經常使用的CSS 處理loaders:

  • Less Loader
  • Sass Loader
  • Stylus Loader

-PostCSS

使用PostCSS來爲CSS代碼自動添加適應不一樣瀏覽器的CSS前綴。

首先安裝postcss-loader 和 autoprefixer(自動添加前綴的插件)

npm install --save-dev postcss-loader autoprefixer

在webpack配置文件中添加postcss-loader,在根目錄新建postcss.config.js。

//webpack.config.js
module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    }
}

postcss.config.js

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

2> babel

Babel實際上是一個編譯JavaScript的平臺,它能夠編譯代碼幫你達到如下目的:

  • 讓你能使用最新的JavaScript代碼(ES6,ES7...),而不用管新標準是否被當前使用的瀏覽器徹底支持;
  • 讓你能使用基於JavaScript進行了拓展的語言,好比React的JSX;

babel轉化語法所需依賴項:

babel-loader: 負責es6語法轉化

babel-core: babel核心包

babel-preset-env: 告訴babel使用哪一種轉碼規則進行文件處理

 

先來一次性安裝依賴包 

// npm一次性安裝多個依賴模塊,模塊之間用空格隔開
npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react

webpack中配置Babel的方法以下:

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: [
                            "env", "react"
                        ]
                    }
                },
                exclude: /node_modules/
            }
        ]
    }
};
Babel其實能夠徹底在  webpack.config.js中進行配置,可是考慮到babel具備很是多的配置選項,在單一的 webpack.config.js文件中進行配置每每使得這個文件顯得太複雜,所以一些開發者支持把babel的配置選項放在一個單獨的名爲 ".babelrc" 的配置文件中。咱們如今的babel的配置並不算複雜,不過以後咱們會再加一些東西,所以如今咱們就提取出相關部分,分兩個配置文件進行配置(webpack會自動調用 .babelrc裏的babel配置選項),以下:
 
webpack.config.js
module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: "babel-loader",
                exclude: /node_modules/
            }
        ]
}

.babelrc

{
  "presets": ["@babel/preset-env"]
}

 

3> Vue-Loader

.vue 文件是一個自定義的文件類型,用類 HTML 語法描述一個 Vue 組件。每一個 .vue 文件包含三種類型的頂級語言塊 <template><script> 和 <style>,還容許添加可選的自定義塊:

<template>
  <div class="example">{{ msg }}</div>
</template>

<script>
export default {
  data () {
    return {
      msg: 'Hello world!'
    }
  }
}
</script>

<style>
.example {
  color: red;
}
</style>

<custom1>
  This could be e.g. documentation for the component.
</custom1>

vue-loader 會解析文件,提取每一個語言塊,若有必要會經過其它 loader 處理,最後將他們組裝成一個 CommonJS 模塊,module.exports 出一個 Vue.js 組件對象。

vue-loader 支持使用非默認語言,好比 CSS 預處理器,預編譯的 HTML 模版語言,經過設置語言塊的 lang 屬性。例如,你能夠像下面這樣使用 Sass 語法編寫樣式:

<style lang="sass">
  /* write Sass! */
</style>

 

7. 插件(Plugins)

插件(Plugins)用來拓展webpack功能,他們會在整個構建過程當中生效,執行相關的任務。

loaders是在打包構建過程當中用來處理源文件的(JSX,Scss, Less),一次處理一個。

plugins並不直接操做單個文件,是對整個構建過程起做用。

 

使用插件的方法:

使用某個插件,須要在webpack配置中的plugins關鍵字部分添加該插件的一個實例(plugins是一個數組)。

例如:添加了一個給打包後代碼添加版本聲明的插件

const webpack = require('webpack');

module.exports = {
...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('版權全部,翻版必究')
    ],
};

 

下面推薦幾個經常使用的插件:

HtmlWebpackPlugin

依據一個簡單的index.html模板,生成一個自動引用你打包後的JS文件的新index.html。這在每次生成的js文件名稱不一樣時很是有用(好比添加了hash值)。

安裝:

npm install --save-dev html-webpack-plugin

webpack.config.js:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    ...
    plugins: [
        new webpack.BannerPlugin('版權全部,翻版必究'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"//new 一個這個插件的實例,並傳入相關的參數
        })
    ],
};

CleanWebpackPlugin

清除目錄的插件。

添加了hash以後,會致使改變文件內容後從新打包時,文件名不一樣而內容愈來愈多,所以這裏介紹另一個很好用的插件clean-webpack-plugin

引入clean-webpack-plugin插件後在配置文件的plugins中作相應配置便可:

 

安裝:

npm install clean-webpack-plugin --save-dev 

webpack.config.js:

整個配置文件,注意插件的配置順序.

  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    ...
    plugins: [
      new CleanWebpackPlugin(['dist']),//清除dist目錄
      new HtmlWebpackPlugin({ //生成一個html頁面指定其title,而後會自動將js文件生成引入js代碼
        title: 'Output Management'
      })
    ]
  };

 

Hot Module Replacement (HMR)

主要是啓動服務後文件能夠進行熱更新,例如css樣式或者js等文件變動,會自動更新到頁面上.只能用於開發環境不能用於生產環境.

它容許你在修改組件代碼後,自動刷新實時預覽修改後的效果。

在webpack中實現HMR也很簡單,只須要作兩項配置

  1. 在webpack配置文件中添加HMR插件;
  2. 在Webpack Dev Server中添加「hot」參數;

webpack.config.js

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin'); module.exports
= { ... devtool: 'eval-source-map', devServer: { contentBase: "./public",//本地服務器所加載的頁面所在的目錄 historyApiFallback: true,//不跳轉 inline: true, hot: true }, ... plugins: [ new webpack.BannerPlugin('版權全部,翻版必究'), new CleanWebpackPlugin(['dist']), new HtmlWebpackPlugin({ template: __dirname + "/app/index.tmpl.html"//new 一個這個插件的實例,並傳入相關的參數 }), new webpack.NamedModulesPlugin(),//添加該插件更容易觀察依賴文件被更新 new webpack.HotModuleReplacementPlugin()//熱加載插件 ], };

目前爲止,咱們已經使用webpack構建了一個完整的開發環境。

產品階段的構建

在產品階段,可能還須要對打包的文件進行額外的處理,好比說優化,壓縮,緩存以及分離CSS和JS。

對於複雜的項目來講,須要複雜的配置,這時候分解配置文件爲多個小的文件可使得事情層次分明。所以最好添加以下配置到配置文件的入口.

process.env.NODE_ENV = 'production'

webpack 配置能夠提煉出來,使用webpack-merge將webpack的配置文件進行合併。

咱們能夠建一個webpack.common.js文件,而後建立一個webpack.prod.js,webpack.dev.js,那麼能夠將prod,dev引入common共同引用參數.

common文件

const path = require('path');
 const CleanWebpackPlugin = require('clean-webpack-plugin');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   entry: {
     app: './src/index.js'
   },
   plugins: [
     new CleanWebpackPlugin(['dist']),
     new HtmlWebpackPlugin({
       title: 'Production'
     })
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist')
   }
 };

生產環境:

webpack提供了一些在發佈階段很是有用的優化插件,它們大多來自於webpack社區,能夠經過npm安裝,經過如下插件能夠完成產品發佈階段所需的功能

  • OccurenceOrderPlugin:爲組件分配ID,經過這個插件webpack能夠分析和優先考慮使用最多的模塊,併爲它們分配最小的ID
  • UglifyJsPlugin:壓縮JS代碼;
  • ExtractTextPlugin:分離CSS和JS文件(將css引入到js文件中,會一塊兒打包成js文件)

OccurenceOrder 和 UglifyJS plugins 都是內置插件,你須要作的只是安裝其它非內置插件

npm install --save-dev extract-text-webpack-plugin

webpack.prod.js

 const merge = require('webpack-merge');
 const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
 const HtmlWebpackPlugin = require('html-webpack-plugin');
 const ExtractTextPlugin = require('extract-text-webpack-plugin');
 const common = require('./webpack.common.js');

 module.exports = merge(common, {
   module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
   plugins: [
     new webpack.BannerPlugin('版權全部,翻版必究'),
     new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"
     }),
     new webpack.optimize.OccurrenceOrderPlugin(),
     new webpack.optimize.UglifyJsPlugin(),
     new ExtractTextPlugin("style.css")
   ]
 });

開發環境:

const merge = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  devtool: 'inline-source-map',
   devServer: {
     contentBase: './dist'
   }
 });

 

 8. 代碼管理

默認的狀況下,webpack會把引用的文件都會build到單獨的文件當中.咱們可能會把一些第三方的模塊放到一個單獨文件裏.

須要對配置文件作以下改動:

     //plugins數組當中添加一下參數
     new webpack.optimize.CommonsChunkPlugin({
       name: 'common' // Specify the common bundle's name.
     })

9. 墊片

當咱們須要全局引入一個變量,咱們可使用ProvidePlugin。(webpack不推薦這樣作,由於會影響到模塊化編程)

每一個js文件就不須要去import引入對應的代碼

plugins: [
      new webpack.ProvidePlugin({
       _: 'lodash'
      })
]

或許只須要部分第三方庫的功能,咱們能夠這樣進行配置

plugins: [
      new webpack.ProvidePlugin({
       _: 'lodash',
       join:['lodash', 'join']//咱們能夠這樣進行配置 ['module', 'child', 'child']
      })
]

10. 緩存

緩存無處不在,使用緩存的最好方法是保證你的文件名和文件內容是匹配的(內容改變,名稱相應改變)

webpack能夠把一個哈希值添加到打包的文件名中,使用方法以下,添加特殊的字符串混合體([name], [id] and [hash])到輸出文件名前。

module.exports = {
..
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: "bundle-[hash].js"
    },
   ...
};

還有個問題webpack默認的hash是根據module.id以及內容生成,而module.id根據解析文件的順序生成,一個重要的問題是每次改動引入的文件,就可能會形成其它文件hahs不一致.

這時候就須要HashedModuleIdsPlugin插件,指定使用Path以及內容做爲hash的內容.

只須要配置文件當中在plugins增長以下配置:

plugins:[
    ...,
    new webpack.HashedModuleIdsPlugin(),
    ...
]


 本文根據https://www.jianshu.com/p/42e11515c10f改寫,加了一些本身的理解,但願對你們有幫助。

相關文章
相關標籤/搜索