直入主題吧,建個文件夾webpack-tut並進入,打開cmd命令窗口,執行npm init -y 命令,創建package.json 文件,轉化為了node 項目,這樣好管理依賴和版本什么的。此時可以學習webpack了。首先要安裝webpack,不過這里要注意,webpack4 把webpack 命令單獨抽了出來,形成了一個單獨的包webpack-cli ,我們安裝webpack的同時要把它安裝上
npm install webpack webpack-cli --save-dev
webpack命令,就是我們在命令窗口中寫的命令,我們在cmd 命令窗口中,輸入webpack, 就會把打包,webpack 就是一個命令。為什么要單獨形成一個包呢?因為webpack-cli 還提供了兩個其它的功能,init 和 migrate命令,使我們快速創建webpack 配置和提供升級遷移。不過這兩個基本不用,了解一下就可以了。我們只要記住安裝webpack的同時安裝上webpack-cli就可以了。
webpack 是模塊打包工具,那就建幾個文件讓它打包,在webpack-tut 文件夾中新建一個src 文件夾,存放我們的源文件,再在src 文件夾中新建index.js 文件和component.js 文件,component.js 文件
export default (text = 'hello world') => { const element = document.createElement('div'); element.innerHTML = text; return element; }
index.js 文件
import component from './component';
document.body.appendChild(component());
怎么打包呢?在webpack4 下,直接執行webpack 命令。在package.json的scripts的字段中,寫上 “build”: “webpack”, 執行npm run build 命令,生成了dist 目錄,表示打包成功了,但也發現了一個WARNING
Webpack4 提供了一個mode 配置項 ,它有兩個選擇: production 和 development, 就是生產模式和開發模式,不同模式,配置肯定不一樣。mode 可以在命令行進行配置, build 命令改成 webpack --mode production 或 webpack --mode development,就配置成功了。
以上就是webpack4 提供的零配置。簡單總結一下,當執行webpack命令,而又沒有配置文件時,webpack會尋找默認的入口文件。默認的入口文件就是項目根目錄下的src目錄下的index.js文件,這也是新建src 目錄和把js文件命名為index.js 的原因。打包后文件,它也定義了默認的輸出路徑,打包后的文件放到dist 目錄中, 文件名為main.js 文件, 同時,它還會根據你指定的mode 進行打包優化。
對於小型的項目,零配置沒有問題,但對於大型的web 項目,它不光有js, 還有css, image 等,零配置就無能為力,還是要退回寫webpack的配置文件。在webpack-tut中新建webpack.config.js 文件(配置文件的默認名稱),配置文件和以前相同,都是entry, output, module, plugins選項。 零配置的時候,webpack 給我們提供了entry 和output, 如果覺得ok的話,可以使用,那配置文件中,只寫module 和plugins 就可以,如果覺得不ok 的話,可以寫entry 和output, 把它覆蓋掉,這都沒有問題, mode 的配置也是如此,可以在命令行中指定,也可以在配置文件中書寫,現在用配置文件的方式,把零配置實現一下
const path = require('path'); module.exports = { mode: 'development', entry: path.join(__dirname, 'src/index.js'), output: { path: path.join(__dirname, 'dist'), filename: 'main.js' } }
npm run build 也打包成功了,最后驗證一下,在根目錄下建一個html 文件,script 引入 dist/main.js, 沒有問題。但這時你也會發現一個問題,改動js文件后,都要執行npm run build 命令,同時要手動刷新瀏覽器才能看效果,非常麻煩,不利於開發,怎么辦? 使用webpack-dev-server, 自動打包,自動刷新
webpack-dev-server 是 webpack自帶的一個小型服務器,它會檢測每個文件的變動,每當有文件改動時,它就會重新打包,然后瀏覽器會自動刷新頁面,這樣就可以時時看到代碼的變動,大大開發了開發效率。這也是所謂的liveload 或hotload(熱更新)。但這里要注意,webpack-dev-server 打包后文件是放到內存中的,而不像npm run build 把文件打包到硬盤上,默認情況下,webpack會把打包生成的文件生成到根目錄下,就相當於在根目下多了打包后的文件,可以通過開發者工具的source 面板來查看一下。
首先 npm install webpack-dev-server --save-dev 安裝它,然后在scripts中,"dev": "webpack-dev-server",
npm run dev 啟動服務器,但當我們更改代碼,頁面刷新但內容並沒有進行改變,這是因為index.html 里面訪問的js 文件是 dist 文件夾中的main.js, 而不是webpack 打包后生成的文件。把dist 文件夾刪除,頁面直接報錯了,找不到main.js 文件,上面已經說了,webpack-dev-server 會把文件打包到項目根目錄下,所以index.html 文件中應該引入當前文件夾下面的main.js。
<body> <script src="./main.js"></script> </body>
npm run dev 和npm run build 命令下,index.html 引入的js 文件路不一致,可以使用html-webpack-plugin 插件解決。npm install html-webpack-plugin --save-dev 安裝,
插件的使用方式也簡單,配置文件中有一個plugins 屬性,它是一個數組,每一個用到的插件都是數組中的一項。具體到每一個插件呢?插件都會暴露出構造函數,通過new 調用,就可以使用,如果插件還有配置項,它就給構造函數傳遞參數,只傳一個對象作為參數
const path = require('path'); const htmlWebpackPlugin = require('html-webpack-plugin'); // 引入插件 module.exports = { mode: 'development', entry: path.join(__dirname, 'src/index.js'), output: { path: path.join(__dirname, 'dist'), filename: 'main.js' }, plugins: [ new htmlWebpackPlugin({ // 插件的使用: new 調用構造函數,配置項就是構造函數的參數(對象形式的參數) template: 'index.html' }) ] }
這時npm run dev 和npm run build都沒有問題。這時我想對webpack-dev-server 進行配置,比如把端口改為9000, 配置文件提供了一個devServer 配置項,這個配置項和entry, output,module並列。devServer的配置是很龐大人,這里只是學幾個簡單實用的配置
module.exports = { devServer: { port: 9000, // 設置端口號 stats: 'errors-only', // 只有產生錯誤的時候,才顯示錯誤信息,日志的輸出等級是error. overlay: true // 當有編譯錯誤的時候,在瀏覽器頁面上顯示。 }, plugins: [ new htmlWebpackPlugin() ] }
重啟服務器,這時看到項目啟動在9000端口下。
這時你也應該發現了一個問題,就是當我們修改配置文件的時候,我們都要重新啟動服務器,這有點麻煩,是不是可以監聽配置文件的變化,自動重啟服務器,這就要用到nodemon, nodemon 就是監聽文件變化,重啟服務器的。先安裝nodemon, npm install nodemon --save-dev, 然后把 dev 命令改為下面
"dev": "nodemon --watch webpack.config.js --exec \"webpack-dev-server \""
命令的意思是 監聽webpack.config.js 的變化,然后執行(exec) webpack-dev-server 命令,注意\'' 雙引號的轉義。
webpack-dev-server 還有兩個配置項需要注意一下:
contentBase: webpack-dev-server 會把所有的靜態文件(css, js, img 等)進行打包,放到服務器根目錄下,供我們訪問。但我們可以訪問服務器中的任何資源,一旦這些資源不是由webpack-dev-server 打包生成的,我們就要指定這些非打包生成的靜態資源,比如index.html 文件,的位置,也就是contentbase,否則就會顯示404. 如果不使用webpack-html-plugin, webpack 是不會打包生成index.html的, 那我們就要手動創建index.html, 這時index.html 文件,就是非webpack-dev-server 打包生成的資源,我們就要指定它的位置。因為我們在瀏覽器中輸入localhost:8080, 我們是向webpack-dev-server 請求index.html 資源,webpack-dev-server 並沒有生成這個文件,所以就會報錯,如果告訴webpack-dev-server, index.html 在什么地方,它就會去找,就不會報錯了。這就是contentbase的作用,webpack-dev-server 會向contentbase 指定的目錄去找它沒有打包生成的文件,你可能說,我們手動創建index.html時,也沒有指定contnetbase, 整個項目也沒有問題,這是因為contentbase的默認值是項目根目錄,而我們創建的index.html 恰巧也在項目根目錄下,所以沒有問題。如果我們在項目根目錄下新建一個文件夾叫public, 然后把index.html 放到里面,你再運行webapck-dev-serve , 它就會報錯,這時就要指定contentbase, 它的取值就很清楚了,index.html(非webpack-dev-server 打包的資源)所在的位置, 絕對路徑和相對路徑都可以, 相對路徑"build", 它是相對於項目根目錄的, 絕對路徑,path.join(__dirname, ‘public’)
proxy: 代理,做過前后端聯調,都知道代理的作用。當我們在本地開發的時候,訪問的服務器是localhost. 但是后端的代碼卻在同事的電腦上,我們要訪問同事的服務,就要設置代理了,要不然訪問的永遠都是本地的服務localhost,一個接口都沒有。我們在請求的接口面前加一個標識,如axios.post(‘/api/login’), /api 就是標識,然后我們再在proxy 配置項里面給這個標識配置一個代理到的真實路徑,如 ‘/api’ : ‘http://102.03.34.58/api’, 那么當我們調用接口的時候,實際上變成了http://102.03.34.58/api/login, 代理配置中的真實路徑,就是會替換到請求中的標示
module.exports = { devServer: { contentBase:'build', proxy: { '/api': 'http://102.03.34.58/api' }, port: 9000, // 設置端口號 stats: 'errors-only', // 只有產生錯誤的時候,才顯示錯誤信息,日志的輸出等級是error. overlay: true // 當有編譯錯誤的時候,在瀏覽器頁面上顯示。 }, plugins: [ new htmlWebpackPlugin() ] }
但有時候,可能是多個同事進行開發,接口沒有那么規范,可能有的以api 開始,有的沒有api, 根本就沒有統一的標識,以上這種配置方式肯定不行, '/api' 標識還可以是一個對象
proxy: { '/api': { target: 'http://102.03.34.58', pathRewrite: { '^/api': '' } } }
這里要注意target 是請求的服務器地址,后面沒有api, 使用這種方式配置以后,代理會在前端請求中的/api前面加上target, 相當於還是請求了 http://102.03.34.58/api/login,所以這里增加了pathRewrite 路徑重寫,所有以/api 開頭的路徑都轉化為 空,所以最后真實的請求路徑中 http://102.03.34.58/login. pathRewrite 中的屬性是正則表達式,^以什么開始, 值 呢?就是匹配到的路徑重寫成會什么。
proxy 中的屬性'/api', 是前端發送請求時,請求接口中的url要加的參數,當真正發送請求時,webpack 服務中配置的代理碰到api 就會攔截,然后把它變成我們配置的真實的路徑