本文是基於我廠基友的Webpack學習系列(一)初學者使用教程 這篇文章作構建。可能基友的文章是基於Mac環境,我是windows環境,在學習時遇到了不少坑,詢問基友,他讓我搞個基於windows環境的,我想了想,正好這幾天需求很少,webpack3.0也來了,那就幹吧!css
Webpack 是當下最熱門的前端資源模塊化管理和打包工具。它能夠將許多鬆散的模塊按照依賴和規則打包成符合生產環境部署的前端資源。還能夠將按需加載的模塊進行代碼分隔,等到實際須要的時候再異步加載。經過
loader
的轉換,任何形式的資源均可以視做模塊,好比 CommonJs 模塊、 AMD 模塊、 ES6 模塊、CSS、圖片、 JSON、Coffeescript、 SASS 等。html
webpack是基於node.js環境的前端自動化打包工具,本文默認你已有必定使用node和npm安裝的基礎。前端
1.1 webpack安裝node
首先新建一個練習文件夾demo,在文件中打開命令終端,輸入下列指令便可安裝webpackwebpack
//全局安裝git
npm install -g webpackes6
//安裝到項目文件夾github
npm install --save-dev webpackweb
安裝完以後,demo裏會多一個node_modules文件夾。正則表達式
接下來輸入
npm init
會自動建立package.json文件。安裝的時候一路回車便可,須要修改後面再進入package.json文件編輯。
package.json文件是webpack的骨架,在裏面能夠看到各個關鍵節點,設置快捷命令等。
1.2 文件夾部署
安裝好上面的東西,咱們開始往demo文件夾塞東西,新建dist,src文件夾、webpack.config.js配置文件來模擬開發環境。最終目錄以下:
demo //webpack的模擬開發文件夾 | - webpack.config.js //配置webpack出入口、插件、loader | - node_modules | - dist //打包輸出文件夾 | - src //開發資源文件夾 | - webpack.js //配置webpack引入資源 | - index.html /* 基礎html文件 | - index.js 基礎js文件 | - index.css 基礎css文件 | - index.scss 基礎scss文件 | - images 基礎圖片文件夾 */ | - img1.png | - img2.png
1.3 配置webpack.config.js
var path = require('path') var webpack = require('webpack') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 } }
按上面步驟安裝後,運行
webpack
便可打包,咱們能夠看到dist文件夾中生成了bundle.js,此時還未壓縮,大小爲3k。
2.1 多入口
咱們看到打包後生成了一個js文件,那假如咱們項目需求生成幾個不一樣類別的js呢?例如當js文件數量多,就模塊化打包後按需加載。
例如:webpack.js和webpack2.js要做爲一個模塊,而index.js和index2.js要做爲另外一個模塊。這時entry和output就要換一種寫法了:
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') module.exports = { // 多入口 entry: { name1: ['./src/webpack','./src/webpack2'], name2: ['./src/index','./src/index2'] }, // 輸出 output: { path: path.join(__dirname, 'dist'), filename: '[name].js' //可重命名 } }
運行打包後能夠在dist裏看到兩個name.js
js模塊化分離打包成功。
2.2 UglifyJsPlugin
UglifyJsPlugin是webpack自帶的核心插件,無需安裝,無需聲明require直接使用。它運行UglifyJs來壓縮輸入文件。
配置webpack.config.js,增長plugins項,裏面放置插件
var path = require('path') var webpack = require('webpack') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ //壓縮 new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ] }
更改配置後,運行webpack打包,能夠看到大小1k(實際是500多字節),壓小了很多。
Webpack 自己只能理解、處理 JavaScript 模塊,若是要處理其餘類型的文件,就須要使用 loader 進行轉換。經過使用不一樣的loader,webpack經過調用外部的腳本或工具能夠對各類各樣的格式的文件進行處理。
總結:Webpack 只能看懂JavaScript ,對於其餘靜態文件,須要用loader幫助理解轉換。
Loaders的配置選項包括如下幾方面:
test
:一個匹配loaders所處理的文件的拓展名的正則表達式(必須)loader
:loader的名稱(必須)include/exclude
:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)(可選);query
:爲loaders提供額外的設置選項(可選)介紹完畢,擼起來!
3.1 編譯CSS
命令安裝 css-loader
npm install --save-dev style-loader css-loader
關於loaders的放置順序:loader解析是從右向左,css-loader用於解析,而style-loader則將解析後的樣式嵌入js代碼。
配置webpack.config.js,增長module項,裏面放置css-loader
var path = require('path') var webpack = require('webpack') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ], //組件loader module: { loaders: [{ // css轉換 test: /\.css$/, loaders: ['style-loader', 'css-loader'] }] } }
配置webpack.js文件,引入index.css
require('./index.css')
運行 webpack 打包,無報錯即編譯成功,能夠在bundle.js文件裏看到壓縮進去的css文件。
注意:這裏有個小坑,網上不少資料都說能夠省略"-loader",即:
loaders: [{ // css轉換 test: /\.css$/, loaders: ['style', 'css'] }]
在windows環境咱們按這種寫法打包一下,會發現報錯:
能夠看到,裏面提到再也不容許省略"-loader"的寫法。因此當咱們寫loader名稱時不要簡寫。
3.2 編譯sass(scss)
命令安裝 sass-loader
npm install --save-dev style-loader sass-loader
發現有飄紅信息:
缺乏 node-sass 依賴,咱們再敲一行命令裝上去就能夠了:
npm install --save-dev style-loader node-sass
而後 npm list 命令看看有沒有安裝成功,後面帶別的名稱便可查其餘分支。如sass-loader
npm list node-sass
配置webpack.config.js,增長sass-loader
var path = require('path') var webpack = require('webpack') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ], //組件loader module: { loaders: [ // css轉換 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass轉換 { test: /\.scss$/, loaders: ['style-loader', 'css-loader', 'sass-loader'] } ] } }
配置webpack.js文件,引入index.scss
require('./index.css') require('./index.scss')
運行 webpack ,沒報錯就是編譯sass成功了。編譯less同理,不贅述。
顧名思義,Plugins 就是webpack的插件。loader只能對靜態文件作處理,而Plugins 不處理單個文件,而是做用於整個構建流程。上面提到的UglifyJsPlugin,也是插件的一種。
4.1 分離CSS和JavaScript ——Extract Text Plugin
進行到這裏,咱們會發現,打包以後的css和js都集合在一塊兒,那到時候引入到頁面上,是放到頭部,仍是尾部呢?顯然都是不可取的:不管放頭部和尾部,js都會阻塞頁面渲染。而插件 Extract Text Plugin 能夠幫助咱們分離css和js。
命令安裝:
npm install --save-dev extract-text-webpack-plugin
配置webpack.config.js
頭部增長Extract Text Plugin插件引入,在plugins那裏new一個你想輸出的樣式文件,最後在loader那增長插件寫法。
var path = require('path') var webpack = require('webpack') var ExtractTextPlugin = require('extract-text-webpack-plugin') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css") ], //組件loader module: { loaders: [ // css轉換 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass轉換 { test: /\.scss$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader', 'sass-loader') } ] } }
注意:沒錯,這裏又有坑。
先運行打包一下:
平常報錯。所幸日誌裏面有提醒咱們:你的代碼老掉牙了,換種寫法吧!
來,把sass轉換那部分用新的格式重寫一遍:
// sass轉換 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback:'style-loader', use:['css-loader','sass-loader'] }) }
運行打包,終於成功,看到dist文件夾裏生成了styles.css和bundle.js
4.2 生成html
經歷各類報錯,終於完成編譯css和js。接下來咱們利用插件html-webpack-plugin來生成集成html
命令安裝:
npm install --save-dev html-webpack-plugin
配置webpack.config.js,添加插件方法和 4.1 同樣
var path = require('path') var webpack = require('webpack') //分離css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css"), new HtmlWebpackPlugin({ template: './src/index.html' }) ], //組件loader module: { loaders: [ // css轉換 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass轉換 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) } ] } }
運行打包,能夠看到再dist文件夾裏生成了一個html文件,webpack自動把css和js分別幫咱們插入到頭部和尾部,這一點很智能。
5.1 圖片打包
讓webpack看得懂圖片格式,須要用到 url-loader ,命令安裝:
npm install --save-dev url-loader
注意:這時候若是繼續往下,到後面打包可能又會報錯,由於url-loader是依賴於 file-loader 才運行的,咱們命令安裝:
npm install --save-dev file-loader
url-loader 還有另一個功能,將小圖片(可自設大小)自動轉爲base64,減小頁面請求數,大讚的功能啊!在html和css寫好背景圖片後,
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分離css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css"), new HtmlWebpackPlugin({ template: './src/index.html' }) ], //組件loader module: { loaders: [ // css轉換 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass轉換 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景圖片轉換 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } ] } }
運行打包後,打開index.html看看效果:
5.2 html中的src圖片
Webpack 不善於處理純粹的 HTML, 要讓webpack能夠打包html中的src圖片,須要用到html-withimg-loader。咱們在index.html頁面中添加一個src的img後命令安裝:
npm install --save-dev html-withimg-loader
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分離css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css"), new HtmlWebpackPlugin({ template: './src/index.html' }) ], //組件loader module: { loaders: [ // css轉換 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass轉換 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景圖片轉換 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }, //讀取html,打包src圖片 { test: /\.html$/, loader: "html-withimg-loader" } ] } }
loader增長html-withimg-loader
而後在webpack.js裏引入index.html:
require('./index.html')
運行打包,沒報錯即成功,打開dist文件夾裏的html看看效果:
能夠看到src的圖片已經被成功引入進來。
5.3 圖片整理
咱們仔細看看輸入文件夾,
圖片直接輸出在dist文件夾,並且名稱被重命名。當圖片數量上去,很是不利於管理。咱們在loader那完善:
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192&name=images/[name].[ext]' },
name字段指定了在輸出目錄(dist)新建一個images文件夾,來存放打包後的圖片,名稱是原圖片命名。
到這裏,基礎頁面已經成型,接下來就是開發了,開發須要調試。那麼咱們怎麼調試這個頁面呢?
若是每次改一次頁面,就要打包一次,嚴重下降效率。運行命令:
webpack --watch
開着這個命令終端,咱們修改的html,css(sass),js等靜態文件均可以經過刷新html頁面直接看到效果。
看到這,有同窗說我F5鍵已摳,懶得每次都要按刷新怎麼辦?
這時候熱加載(HMR)能夠幫到你,首先,跑起一個服務。
6.1 輕量的node.js express服務器——Webpack-dev-server
webpack能夠跑起一個微型服務器,直接做用於資源文件,方便咱們開發調試。其中熱加載是一個很是實用的功能。命令安裝Webpack-dev-server
npm install --save-dev webpack-dev-server
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分離css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: [ './node_modules/webpack-dev-server/client?http://localhost:8080', './node_modules/webpack/hot/dev-server', './src/webpack' ], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css"), new HtmlWebpackPlugin({ template: './src/index.html' }), new webpack.HotModuleReplacementPlugin() ], //組件loader module: { loaders: [ // css轉換 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass轉換 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景圖片轉換 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } ] }, devServer: { contentBase: './dist', hot: true } }
增長兩個入口,用於關聯服務器;devServer裏面的contentBase指向你的輸出文件夾dist(或其餘命名),hot表示是否開啓熱加載。
能夠從入口看出項目服務訪問地址是:http://localhost:8080。
跑服務的命令是:
webpack-dev-server --config webpack.config.js
每次都這麼輸入太累贅,能夠在package.json裏配置命令:
"scripts": { "dev": "webpack-dev-server --config webpack.config.js" },
這樣每次跑服務,直接:
npm run dev
就能夠了,固然你也能夠自由更改端口號,例如把8080改成8888:
"scripts": { "dev": "webpack-dev-server --host localhost --port 8888 --config webpack.config.js" },
運行服務命名,在瀏覽器輸入相應端口號,就能夠看到運行於webpack服務的頁面了
6.2 熱加載(HMR)
終於到重點了。跑起來的8080服務頁面,目標調試須要刷新頁面才能生效,但只要咱們使用HMR,只要代碼有改動,無需刷新頁面,瀏覽器會自動更新。
在上文的圖片模塊中(5.2),已引入了html-withimg-loader ——能夠將html轉爲字符串的loader,在這就省略引入解析html-loader的步驟。
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分離css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: [ './node_modules/webpack-dev-server/client?http://localhost:8080', './node_modules/webpack/hot/dev-server', './src/webpack' ], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), //分離css和js new ExtractTextPlugin("styles.css"), //生成html頁面 new HtmlWebpackPlugin({ template: './src/index.html' }), //熱加載 new webpack.HotModuleReplacementPlugin() ], //組件loader module: { loaders: [ // css轉換 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass轉換 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景圖片轉換 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }, //讀取html,熱加載 { test: /\.html$/, loader: "html-withimg-loader" } ] }, devServer: { contentBase: './dist', hot: true } }
在plugins增長熱加載插件;loader增長raw-loader,正則匹配html。
運行:
npm run dev
如今你隨意修改頁面內容,會發現不用手動刷新瀏覽器就自動更新了你所更改的內容。
Babel 是一款轉碼編譯器,能夠很方便地將 ES六、ES7 等當前瀏覽器不兼容的 JavaScript 新特性轉碼爲 ES5 等當前瀏覽器廣泛兼容的代碼。將二者結合起來能夠很方便地在項目中一邊使用 ES6 編寫代碼,一邊自動生成 ES5 代碼。
Babel有不一樣的插件,能夠按需安裝:http://babeljs.io/docs/plugins/preset-es2015/
安裝相關組件:
//安裝加載器 babel-loader 和 Babel 的 API 代碼 babel-core
npm install --save-dev babel-loader babel-core安裝 ES2015(ES6)的代碼,用於轉碼
npm install babel-preset-es2015 --save-dev//用於轉換一些 ES6 的新 API,如 Generator,Promise 等
npm install --save babel-polyfill
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分離css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: [ './node_modules/webpack-dev-server/client?http://localhost:8080', './node_modules/webpack/hot/dev-server', './node_modules/babel-polyfill', './src/webpack', './src/index' ], // bundle輸出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ // new webpack.optimize.UglifyJsPlugin({ // compress: { // warnings: false // } // }), //分離css和js new ExtractTextPlugin("styles.css"), //生成html頁面 new HtmlWebpackPlugin({ template: './src/index.html' }), //熱加載 new webpack.HotModuleReplacementPlugin() ], //組件loader module: { loaders: [ // css轉換 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass轉換 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景圖片轉換 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192&name=images/[name].[ext]' }, //讀取html,打包src圖片 { test: /\.html$/, loader: "html-withimg-loader" }, //編譯es6,轉化爲es5 { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', query: { presets: ['es2015'] } } ] }, devServer: { contentBase: './dist', hot: true } }
entry入口那裏增長了babel-polyfill,loader增長babel-loader。因爲要驗證打包後的js是否已編譯轉爲es5,因此這裏註釋代碼壓縮的插件。
在index.js裏任意輸入一個es6語法的語句:
而後再打開打包後的bundle.js文件,拉到最下面,能夠發現該es6語句已被轉爲es5語法輸出:
編譯轉碼成功。
至此webpack打包大體的步驟已完成。 若是對配置文件或者目錄結構有疑問,想看示例代碼的能夠帶個人github:https://github.com/stzhongjie/webpack 上下載源碼。
至此webpack打包大體的步驟已完成。在行文過程當中,發現了幾個問題不得其解,網上谷歌搜索也搜不出個因此然,故在這裏把問題拋出,但願知道的大神不吝賜教。
一:熱加載那裏,我發現假如引用的是css文件,修改內容熱加載有效果,但引用scss文件熱加載就失效了,如何讓引用scss文件也能實現熱加載呢?
二:html-withimg-loader和raw-loader的區別是什麼呢?網上的解釋都說是對html解析成字符串,讓js讀懂。網有些文章,熱加載用的loader是raw-loader,但我發現用html-withimg-loader也能跑起來。