關於webpackjavascript
webpakc的是模塊打包器.而不是任務執行器。css
它作的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),並將其轉換和打包爲合適的格式供瀏覽器使用。
webpack也提供了便捷的打包流程,項目構建,插件管理等等.
爲更好的構建項目,從開發到生產都一一提供瞭解決方案.
Vue官方也推薦使用的vue-loader也是基於webpack的.html
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
Loaders
是
webpack
提供的最激動人心的功能之一。經過使用不一樣的
loader
,
webpack
有能力調用外部的腳本或工具,實現對不一樣格式的文件的處理,好比說分析轉換scss爲css,或者把下一代的JS文件(ES6,ES7)轉換爲現代瀏覽器兼容的JS文件,對React的開發而言,合適的Loaders能夠把React的中用到的JSX文件轉換爲JS文件。
webpack.config.js
中的modules
關鍵字下進行配置。
test
:一個用以匹配loaders所處理文件的拓展名的正則表達式(必須)loader
:loader的名稱(必須)include/exclude
:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)(可選);query
:爲loaders提供額外的設置選項(可選)css-loader
和
style-loader
,兩者處理的任務不一樣。
css-loader
使你可以使用相似
@import
和
url(...)
的方法實現
require()
的功能;
style-loader
將全部的計算後的樣式加入頁面中;
安裝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的拓展,它們容許你使用相似於variables
, nesting
, mixins
, inheritance
等不存在於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的平臺,它能夠編譯代碼幫你達到如下目的:
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/ } ] } };
webpack.config.js
中進行配置,可是考慮到babel具備很是多的配置選項,在單一的
webpack.config.js
文件中進行配置每每使得這個文件顯得太複雜,所以一些開發者支持把babel的配置選項放在一個單獨的名爲 ".babelrc" 的配置文件中。咱們如今的babel的配置並不算複雜,不過以後咱們會再加一些東西,所以如今咱們就提取出相關部分,分兩個配置文件進行配置(webpack會自動調用
.babelrc
裏的babel配置選項),以下:
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('版權全部,翻版必究') ], };
下面推薦幾個經常使用的插件:
依據一個簡單的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 一個這個插件的實例,並傳入相關的參數 }) ], };
清除目錄的插件。
添加了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' }) ] };
主要是啓動服務後文件能夠進行熱更新,例如css樣式或者js等文件變動,會自動更新到頁面上.只能用於開發環境不能用於生產環境.
它容許你在修改組件代碼後,自動刷新實時預覽修改後的效果。
在webpack中實現HMR也很簡單,只須要作兩項配置
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能夠分析和優先考慮使用最多的模塊,併爲它們分配最小的IDUglifyJsPlugin
:壓縮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改寫,加了一些本身的理解,但願對你們有幫助。