webpack的基本使用 webpack 本質上是一個打包工具,它會根據代碼的內容解析模塊依賴,幫助我們把多個模塊的代碼打包。借用 webpack 官網的圖片: 雖然webpack4.x的版本可以零配置開始構建,但是在實際的項目中需要其它的一些功能,還是需要一個配置文件。 安裝 下麵一步一步講解配置 ...
webpack的基本使用
webpack 本質上是一個打包工具,它會根據代碼的內容解析模塊依賴,幫助我們把多個模塊的代碼打包。借用 webpack 官網的圖片:
雖然webpack4.x的版本可以零配置開始構建,但是在實際的項目中需要其它的一些功能,還是需要一個配置文件。
安裝
下麵一步一步講解配置一個基本的前端開發環境過程。
首先自己環境中安裝了有node(自帶npm)。如果你的項目中沒有package.json,那麼需要使用npm init。
會在項目下生成一個package.json文件,其中會有如下代碼:
{ "name": "test", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }
我們現在來使用npm來安裝webpack,可以作為一個全局的命令來使用:
npm install webpack webpack-cli -g
其中webpack-cli是使用webpack的命令行工具。在 4.x 版本之後不再作為 webpack 的依賴了,我們使用時需要單獨安裝這個工具。
更多的時候我們是把webpack作為項目的依賴來安裝使用的。
npm install webpack webpack-cli -D
package.json文件就會多瞭如下配置:
"devDependencies": { "webpack": "^4.27.1", "webpack-cli": "^3.1.2" }
我們在package.json中添加一個npm scripts:
代碼如下:
"scripts": { "build": "webpack --mode production" }, "devDependencies": { "webpack": "^4.27.1", "webpack-cli": "^3.1.2" }
然後我們創建一個'./src/index.js',其中index.js中的代碼任意寫,如:
export default { a:'字元串' }
然後執行npm run build後會在項目下增加了一個dist文件夾,裡面存放了webpack構建好的main.js文件。
因為是作為項目依賴進行安裝,所以不會有全局的命令,npm 會幫助我們在當前項目依賴中尋找對應的命令執行,如果是全局安裝的 webpack,直接執行webpack --mode production就可以。
webpack重要的幾個概念
webpack 的幾個重要的概念:入口,loader,plugin,輸出。
入口
所謂入口,就是webpack的構建入口。webpack會讀取這個文件,並從它這兒開始解析依賴,然後進行打包。如上面操作,一開始webpack預設的構建入口就是'./src/index.js'。
在我們的項目中,如果是單頁面應用,一般就只有一個入口;如果是多頁面,那麼就會配置成一個頁面一個構建入口。
入口可以使用entry欄位來設置,webpack支持配置多個入口進行構建打包:
module.exports = { entry: './src/index.js' } // 上述配置等同於 module.exports = { entry: { main: './src/index.js' } } // 或者配置多個入口 module.exports = { entry: { foo: './src/page-foo.js', bar: './src/page-bar.js', // ... } } // 使用數組來對多個文件進行打包 module.exports = { entry: { main: [ './src/foo.js', './src/bar.js' ] } }
最後的例子,可以理解為多個文件作為一個入口,webpack 會解析兩個文件的依賴後進行打包。
loader
webpack 中提供一種處理多種文件格式的機制,便是使用 loader。我們可以把 loader 理解為是一個轉換器,負責把某種文件格式的內容轉換成 webpack 可以支持打包的模塊。
舉個例子,比如你的入口文件index.js引入了css樣式,那麼構建的時候就需要用css-loader來處理這些.css文件,同時還需要style-loader。最終打包的結果就是把不同類型的文件都解析成js代碼,以便在打包後能在瀏覽器中運行。
當我們需要使用不同的 loader 來解析處理不同類型的文件時,我們可以在module.rules欄位下配置相關的規則,比如使用babel來轉化js代碼:
module: { // ... rules: [ { test: /\.jsx?/, // 匹配文件路徑的正則表達式,通常我們都是匹配文件類型尾碼 include: [ path.resolve(__dirname, 'src') // 指定哪些路徑下的文件需要經過 loader 處理 ], use: 'babel-loader', // 指定使用的 loader }, ], }
後面有筆記會詳細記錄下loader的使用以及怎樣開發loader。
plugin
在webpack的構建工作中,除了用loader來處理模塊代碼的轉換,剩下的工作就是用plugin來完成,下麵列舉常用的幾個:
- 壓縮JS代碼:uglifyjs-webpack-plugin
- 關聯JS生成html頁面:html-webpack-plugin
- 生成CSS文件: extract-text-webpack-plugin
- 定義環境變數:DefinePlugin
JS代碼壓縮配置如下:
const UglifyPlugin = require('uglifyjs-webpack-plugin') module.exports = { plugins: [ new UglifyPlugin() ], }
輸出
webpack 的輸出即指 webpack 最終構建出來的靜態文件。構建結果的文件名、路徑等都是可以配置的,使用output欄位:
module.exports = { // ... output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js', }, } // 或者多個入口生成不同文件 module.exports = { entry: { foo: './src/foo.js', bar: './src/bar.js', }, output: { filename: '[name].js', path: __dirname + '/dist', }, } // 路徑中使用 hash,每次構建時會有一個不同 hash 值,避免發佈新版本時線上使用瀏覽器緩存 module.exports = { // ... output: { filename: '[name].js', path: __dirname + '/dist/[hash]', }, }
我們剛開始構建的webpack,預設的構建結果就是'./dist/main.js'。
一個簡單的webpack配置例子
上面總結了幾個webpack的重要概念後,來看一個簡單的配置例子,webpack運行時預設讀取項目下的webpack.config.js文件作為配置,那麼我們現在就在項目下創建一個webpack.config.js文件:
const path = require('path') const UglifyPlugin = require('uglifyjs-webpack-plugin') //js壓縮插件 module.exports = { entry:'./src/index.js', output:{ path:path.resolve(__dirname,'dist'), filename:'bundle.js' }, module:{ rules:[ { test:/\.jsx?/,//匹配js,jsx文件 include:[ path.resolve(__dirname,'src') ], use:'babel-loader' } ] }, // 代碼模塊路徑解析的配置 resolve: { modules: [ "node_modules", path.resolve(__dirname, 'src') ], extensions: [".wasm", ".mjs", ".js", ".json", ".jsx"], }, plugins:[ new UglifyPlugin() //使用uglifyjs-webpack-plugin壓縮JS代碼 //根據上面第一次的構建,你會發現webpack預設使用了JS的代碼壓縮插件 //這其實也是命令中的 --mode production的效果 ] }
當你直接運行npm run build命令的時候,會報錯Cannot find module 'uglifyjs-webpack-plugin'。這兒你需要安裝如下內容:
- 1.npm install uglifyjs-webpack-plugin --save-dev
- 2.npm install -D babel-loader@7 babel-core babel-preset-env webpack
- 3.最後執行npm run build能看到在dist文件夾下生成了一個bundle.js構建完成的文件。
vue腳手架vue-cli的webpack配置
vue-cli 使用 webpack 模板生成的項目文件中,webpack 相關配置存放在 build 目錄下。現在的腳手架vue-cli的webpack好像還是用的webpack3.x版本,要註意下版本區別。
構建基本的前端開發環境
我們構建基本的前端開發環境需要做哪些事情:
- 構建我們發佈需要的 HTML、CSS、JS 文件
- 使用 CSS 預處理器來編寫樣式
- 處理和壓縮圖片
- 使用 Babel 來支持 ES 新特性
- 本地提供靜態服務以方便開發調試
下麵圍繞這些要求要構建開發環境。
JS關聯HTML頁面html-webpack-plugin
當我們構建打包完成生成了JS文件,怎樣把JS文件跟html頁面相關聯呢,也就是html怎樣引入js文件。當然可以使用script標簽引入js文件,但是如果打包構建的js路徑變化或者使用了hash命名,那麼直接引入js文件就不合理了,這時就需要使用html-webpack-plugin
把html-webpack-plugin安裝到項目依賴中去:
npm install html-webpack-plugin -D
首先自己按照下列目錄創建模板html文件,‘./src/assets/index.html’,html內容隨便寫,如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>這是構建的第一個web頁面</title> </head> <body> </body> </html>
將html-webpack-plugin配置到webpack.config.js中的plugins列表中:
module.exports = { // ... plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', // 配置輸出文件名和路徑 template: 'assets/index.html', // 配置文件模板 }), ], }
這樣,通過 html-webpack-plugin 就可以將我們的頁面和構建 JS 關聯起來,這樣將會產生一個包含以下內容的文件dist/index.html。打開index.html可以看到構建後的代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>這是構建的第一個web頁面</title> </head> <body> <script type="text/javascript" src="bundle.js"></script></body> </html>
詳細瞭解可參考文檔html-webpack-plugin, 官網提供的例子html-webpack-plugin/examples/
構建CSS
我們構建CSS需要使用css-loader和style-loader。
module.exports = { module: { rules: [ // ... { test: /\.css/, include: [ path.resolve(__dirname, 'src'), ], use: [ 'style-loader', 'css-loader', ], }, ], } }
註:style-loader 和 css-loader 都是單獨的 node package,需要安裝。
我們創建一個index.css,在index.js中引入:
import './index.css'
index.css裡面隨便編寫一段css代碼:
.title{ font-weight: bold; font-size:20px; color:red; }
模板index.html改成如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <div class="title">這是一個主題</div> </body> </html>
安裝style-loader與css-loader:
npm install style-loader css-loader --save-dev
現在執行npm run build,然後去看生成的index.html,效果有了,css樣式添加上了。但是並沒有生成css文件。
解釋下css-loader跟style-loader的作用:
- css-loader 負責解析 CSS 代碼,主要是為了處理 CSS 中的依賴,例如@import
和url()
等引用外部文件的聲明; - style-loader 會將 css-loader 解析的結果轉變成 JS 代碼,運行時動態插入style標簽來讓 CSS 代碼生效。
如果需要單獨把 CSS 文件分離出來,我們需要使用extract-text-webpack-plugin.
由於webpack4.x的extract-text-webpack-plugin版本還沒有發佈正式版,安裝的時候需要指定使用它的 alpha 版本:
npm install extract-text-webpack-plugin@next -D
配置:
const ExtractTextPlugin = require('extract-text-webpack-plugin') module.exports = { // ... module: { rules: [ { test: /\.css$/, // 因為這個插件需要干涉模塊轉換的內容,所以需要使用它對應的 loader use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader', }), }, ], }, plugins: [ // 引入插件,配置文件名,這裡同樣可以使用 [hash] new ExtractTextPlugin('index.css'), ], }
然後就會在dist文件夾下多生成一個index.css文件。詳細可參考:extract-text-webpack-plugin
CSS 預處理器
通常我們在編寫css的時候,經常使用less或者sass等css預處理器,我們以less為例,我們把index.css改成index.less如下:
@fontSize:20px; .title{ font-weight: bold; font-size:@fontSize; color:red; }
安裝less-loader,官網文檔對應loader:
npm install --save-dev less-loader less
對應的配置文件修改為:
module.exports = { // ... module: { rules: [ { test: /\.less$/, // 因為這個插件需要干涉模塊轉換的內容,所以需要使用它對應的 loader use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: [ 'css-loader', 'less-loader', ], }), }, ], }, // ... }
處理圖片文件file-loader及增強版url-loader
file-loader
雖然css-loader會解析樣式中用url()引用的文件路徑,但是圖片有jpg/png/gif格式,webpack處理不了,需要使用一個loader配置才行,這就用到了file-loader。
file-loader 可以用於處理很多類型的文件,它的主要作用是直接輸出文件,把構建後的文件路徑返回。
配置如下:
module.exports = { // ... module: { rules: [ { test: /\.(png|jpg|gif)$/, use: [ { loader: 'file-loader', options: {}, }, ], }, ], }, }
安裝file-loader,官方文檔file-loader:
npm install --save-dev file-loader
我在index.js引入一張圖片:
import '../assets/a.jpg'
運行結果預設在dist目錄下生成了78414f2de9fc47d29f335727a717bc3d.jpg。預設情況下,生成的文件的文件名就是文件內容的 MD5 哈希值並會保留所引用資源的原始擴展名。
當然也可以配置輸出路徑,文件名稱等,如下:
{ test:/\.(jpg|png|gif)$/, use:[ { loader:'file-loader', options:{ name: '[path][name].[ext]', outputPath: 'images/' } } ] }
url-loader
安裝url-loader,詳細文檔請參考官網url-loader:
url-loader功能類似於file-loader
,但是在文件大小(單位 byte)低於指定的限制時,可以返回一個 DataURL。
npm install --save-dev url-loader
配置:
module.exports = { module: { rules: [ { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] } ] } }
使用 Babel
Babel是一個讓我們能夠使用 ES 新特性的 JS 編譯工具,我們可以在 webpack 中配置 Babel,以便使用 ES6、ES7 標準來編寫 JS 代碼。
前面已經寫過配置了,代碼如下:
module.exports = { // ... module: { rules: [ { test: /\.jsx?/, // 支持 js 和 jsx include: [ path.resolve(__dirname, 'src'), // src 目錄下的才需要經過 babel-loader 處理 ], loader: 'babel-loader', }, ], }, }
Babel 的相關配置可以在目錄下使用 .babelrc 文件來處理,詳細參考 Babel 官方文檔 .babelrc
使用 webpack-dev-server啟動靜態服務
我們可以使用 webpack-dev-server 在本地開啟一個簡單的靜態服務來進行開發。
安裝webpack-dev-server:
npm install webpack-dev-server --save-dev
然後添加啟動命令到 package.json 中:
"scripts": { "build": "webpack --mode production", "start": "webpack-dev-server --mode development" }
然後運行npm run start,然後就可以訪問 http://localhost:8080/ 來查看你的頁面了。預設是訪問 index.html,如果是其他頁面要註意訪問的 URL 是否正確。
總結
根據上面的配置,我們已經完成了配置一個簡單的前端開發環境,實現了:構建 HTML、CSS、JS 文件、使用 CSS 預處理器來編寫樣式、處理和壓縮圖片、使用 Babel、方便開發調試的靜態服務。下麵的筆記會記錄webpack的一些細節來更好的瞭解webpack。