一份比较详细的 webpack 4.x 手工配置基础开发环境 附源码
重新書寫了博客內容,希望可以更好的呈現該有的知識點。
bundle.js 指的是 webpack 打包后的文件。
小劇場
項目經理:我們要開始一個新的項目,褲襠你來負責項目構建吧。
我:好的沒問題,經理請稍等。
我:好了,我們開始吧。
項目經理:接下來呢?
我:接下來沒了,可以開發了。
項目經理:褲襠啊,速度快是好事,但是我看你每次都是那么幾步,能不能來點不一樣的,你看那些面試官,面試手寫一個 webpack 4.x 的配置,你知道怎么寫么?
我:。。。。。。
項目經理:(拂袖而去,遠遠地聽到空中傳來一句話)年輕人,切勿急躁,穩中求勝啊。
我:項目急的時候你不是這么說的。
項目經理:褲襠你說啥?
我:經理你說得對。
前言
在我們在面對一個新的項目的時候,網上的大量優秀的模板可以使我們少走很多彎路,可以把主要的精力放在業務上,等到后期項目龐大了,業務復雜了的時候再去做一些優化,這其中包括項目打包速度優化,項目打包體積優化(也可以看做是首屏加載優化),等等,但是,身為一個愛折騰的程序猿,面對這些模板,是的,我很好奇!
當然,文章開始之前,附上該項目的地址,github@jsjzh,所有的代碼我都加上了注釋,希望大家看完之后可以有所收獲,最好能賞個 star 啦!=3=
git clone https://github.com/jsjzh/my-webpack-template.git cd my-webpack-template npm install npm startwebpack 4.x 的那些新玩意兒
在最新的 官方文檔 中,有兩個新的配置項,mode 和 optimization,我們就從這兩個入手,看看 webpack .4x 有什么新東西。
下面會介紹因為你配置了不同的 mode 之后,你的代碼會受到的不同對待。
mode 是個啥
這個配置項是區分 webpack 4.x 和其他版本最方便的手段,webpack 4.x 給我們提供了兩個模式用作開發和生產的模式,這兩個模式下 webpack 默默給我們開啟了不少優化手段,當然,這些優化手段我們也是可以配置的,就是在 optimization 這個配置項中,我們也可以自己增加 optimization 選項對項目進行更細的優化。
production | development | none下面我會對 mode 的兩個值 production 和 development 進行比較詳細的說明,看看 webpack 到底偷偷給我們開啟了什么優化。
prod 和 dev 相同的優化
mode: production || development 時,webpack 都會開啟的優化。
{"mode": "production" || "development","optimization": {// 如果 子模塊 和 父模塊 都加載了同一個 A模塊 的時候,開啟這個選項將會告訴 webpack 跳過在 子模塊 中對 A模塊 的檢索,這可以加快打包速度。"removeAvailableModules": true,// webpack 將會不會去打包一個空的模塊。"removeEmptyChunks": true,// 告訴 webpack 合并一些包含了相同模塊的模塊。"mergeDuplicateChunks": true,// 會在 process.env.NODE_ENV 中傳入當前的 mode 環境。"nodeEnv": "production" || "development"} }prod 和 dev 不同的優化
mode: production 時,webpack 開啟的優化。
{"mode": "production","optimization": {// 告訴 webpack 確定和標記塊,這些塊是其他塊的子集,當更大的塊已經被加載時,不需要加載這些子集。"flagIncludedChunks": true,// 告訴 webpack 找出一個模塊的順序,這可以使打包出來的入口 bundle.js 最小化。"occurrenceOrder": true,// 確定每個模塊下導出被使用的。"usedExports": true,// 告訴 webpack 查找可以安全地連接到單個模塊的模塊圖的片段。取決于優化。"concatenateModules": true,// 使用 UglifyjsWebpackPlugin 進行代碼壓縮。"minimize": true},// 性能相關配置"performance": {"hints": "error",// ...} }mode: development 時,webpack 開啟的優化。
{"mode": "development",// 生成 source map 的格式選擇,這個選項可以直接影響構建速度。"devtool": "eval",// 緩存模塊,避免在未更改時重建它們。"cache": true,"module": {// 緩存已解決的依賴項,避免重新解析它們。"unsafeCache": true},"output": {// 在 bundle.js 中引入項目所包含模塊的注釋信息。"pathinfo": true},"optimization": {// 在可能的情況下確定每個模塊的導出。"providedExports": true,// 找到 chunk 中共享的模塊,取出來生成單獨的 chunk。// 該配置用于代碼分割打包,取代了曾經的 CommonsChunkPlugin 插件。"splitChunks": true,// 為 webpack 運行時代碼創建單獨的 chunk。"runtimeChunk": true,// 編譯錯誤時不寫入到輸出。// 取代了曾經的 NoEmitOnErrorsPlugin 插件。"noEmitOnErrors": true,// 給模塊更有意義更方便調試的名稱。// 取代了曾經的 NamedModulesPlugin 插件。"namedModules": true,// 給 chunk 更有意義更方便調試的名稱。"namedChunks": true,} }webpack 4.x 基礎版開發環境詳細配置
基礎版擁有 npm start 之后 打開一個新的網頁,并且更改 js 會自動更新的功能,不包含對 ES6 語法的轉義以及 css 打包,image 圖片轉為 dataURL 的功能。
先來一套組合拳,創建一個項目文件夾,并初始化項目。
md my-webpack-template cd my-webpack-template npm init -y接著可以參考我的目錄結構(列出主要的文件,只針對 dev 環境)。
+---my-webpack-template | index.html | package.json +---build | utils.js | build-server.js | webpack.base.conf.js | webpack.dev.conf.js +---config | index.js | dev.env.js +---src | index.js安裝所需依賴。
webpack 和 webpack-cli 曾經是在一起的,在 4.x 版本中進行了拆分,所以如果不好好同時安裝他們倆是不行的哦。
不推薦全局安裝 webpack,這會導致命令行運行 webpack 的時候鎖定版本。 npm install webpack webpack-cli -Dwebpack-dev-server 是一個專門用于開發環境使用的集成了眾多功能的環境,基于 express,擁有即時編譯代碼(webapck-dev-middleware),熱更新(webpack-hot-middleware),自動打開瀏覽器(opn),對 HTML5 中 history 做特殊處理(connect-history-api-fallback)等等功能。
對于開發環境,即時編譯的代碼不會存儲在硬盤中而是在內存中,這是由 webapck-dev-middleware 完成的功能。 npm install webpack-dev-server -D用于合并 webpack 配置的,一般我們會把 webpack 的 base 配置和 dev 配置 和 prod 配置分開寫,用這個工具就可以很方便的合并 base 和 dev 的配置。
npm install webpack-merge -D一個用于處理打包這個進程的插件,可以清除打包時候殘留的控制臺信息,并且可以在控制臺打印出打包成功之后的文字提示,當然,對于打包錯誤之后的回調也是有的。
npm install friendly-errors-webpack-plugin -D這個相對來說各位看官應該用的很多了吧,用于生成一個 html 文件,并且可以在底部注入通過 webpack 打包好的 bundle.js 文件。
npm install html-webpack-plugin -D一個尋找可用端口的工具,當你配置的端口被占用時,這個工具會自動尋找一個可用的端口。
npm install portfinder -D配置 package.json 中的運行腳本
接著,安裝完了依賴我們需要配置 npm 運行時候的腳本了。
當你在命令行直接輸入 webpack 報錯的,并且確信自己已經安裝了 webpack 的時候,試試直接配置 package.json 中的 scripts,說不定你安裝的是項目中的 webpack,而 package.json 中運行的腳本將優先該項目的環境。 "scripts": {"dev": "webpack-dev-server --inline --progress --config build/build-server.js","start": "npm run dev" }build/webpack.base.conf.js 配置詳解
先來配置 webpack 基礎的配置,這里的配置 prod 和 dev 相同。
// 將一些配置寫在 config/index.js 中,方便直接獲取 var config = require("../config");// 獲取項目的初始目錄,包裝了個小函數 function resolve(file) {return path.resolve(__dirname, "../", file) }module.exports = {// webpack 處理打包文件的時候的初始目錄context: resolve("./"),// 入口文件,webapck 4.x 默認的就是 src/index.jsentry: {app: "./src/index.js"},// 輸出文件的目錄output: {path: config.build.assetsRoot,filename: "[name].js",publicPath: process.env.NODE_ENV === "production" ?config.build.assetsPublicPath : config.dev.assetsPublicPath} }build/webpack.dev.conf.js 配置詳解
// 將一些配置寫在 config/index.js 中,方便直接獲取 var config = require("../config"); var devConfig = config.dev; // 一些工具函數 var utils = require("./utils"); // nodeJs 內置的函數,專門用來解析路徑 var path = require("path"); // 大名鼎鼎的 webpack var webpack = require("webpack"); var merge = require("webpack-merge"); var HtmlWebpackPlugin = require("html-webpack-plugin"); var webpackBaseConfig = require("./webpack.base.conf");module.exports = merge(webpackBaseConfig,{// 配置開發環境 modemode: "development",// 一句話,這是個方便開發工具進行代碼定位的配置// 但是不同的配置會影響編譯速度和打包速度,這里使用了和 vue-cli 同樣的配置devtool: devConfig.devtool,// 使用了 webpack-dev-server 之后就需要有的配置// 在這里可以配置詳細的開發環境devServer: {// 當我們在 package.json 中使用 webpack-dev-server --inline 模式的時候// 我們在 chrome 的開發工具的控制臺 console 可以看到信息種類// 可選 none error warning infoclientLogLevel: "warning",// 不用擔心:要解決這個問題,你所需要做的就是在你的服務器上添加一個簡單的萬能回退路線。如果URL不匹配任何靜態資產,那么它應該服務于相同的索引。你的應用程序所在的html頁面。又漂亮! --- by vue-router// 這個配置就是應用了 connect-history-api-fallback 插件// 想象一個場景,vue 開發,我們利用 vue-router 的 history 模式進行單頁面中的頁面跳轉// www.demo.com 跳轉去 www.demo.com/list// 看起來沒毛病,vue-router 中只要配置了 list 的路由即可// 但是,當你刷新頁面的時候,瀏覽器會去向服務器請求 www.demo.com/list 的資源,這想當然是找不到的// 這個中間件就是會自動捕獲這個錯誤,然后將它重新定位到 index.htmlhistoryApiFallback: {rewrites: [{from: /.*/,to: path.posix.join(devConfig.assetsPublicPath,"index.html")}]},// webpack 最有用的功能之一 --- by webpack// 熱更新裝置啟動hot: true,// 告訴 webpack-dev-server 搭建服務器的時候從哪里獲取靜態文件// 默認情況下,將使用當前工作目錄作為提供靜態文件的目錄// contentBase: false,// 搭建的開發服務器啟動 gzip 壓縮compress: true,// 搭建的開發服務器的 host,這里使用了一個函數去獲取當前電腦的局域網 ip// 這個可以獲取你的電腦的 ip 地址,然后開發服務器就可以搭建在局域網里// 如果有一同開發的小伙伴,在同一局域網內就可以直接訪問地址看到你的頁面// 同樣,這個也適用于手機,連上同一個 wifi 之后就可以在手機上實時看到修改的效果host: utils.getIPAdress(),// 開發服務器的端口號// 但是后面我們會用到 portfinder 插件,如果真的 config/index.js 中的端口被占用了// 那這個插件會以這個為 basePort 去找一個沒有被占用的端口port: devConfig.port,// 是否要服務器搭建完成之后自動打開瀏覽器open: devConfig.autoOpenBrowser,// 是否打開發現錯誤之后在瀏覽器全屏幕顯示錯誤信息功能overlay: devConfig.errorOverlay ? {warnings: false,errors: true} : false,// 此路徑下的打包文件可在瀏覽器中訪問// 假設服務器運行在 http://localhost:8080 并且 output.filename 被設置為 bundle.js// 默認 publicPath 是 "/",所以 bundle.js 可以通過 http://localhost:8080/bundle.js 訪問publicPath: devConfig.assetsPublicPath,// 啟動接口訪問代理proxy: devConfig.proxyTable,// 啟用 quiet 后,除了初始啟動信息之外的任何內容都不會被打印到控制臺// 和 FriendlyErrorsPlugin 配合食用更佳quiet: true,// 開啟監聽文件修改的功能,在 webpack-dev-server 和 webpack-dev-middleware 中是默認開始的// watch: true,// 關于上面 watch 的一些選項配置watchOptions: {// 排除一些文件監聽,這有利于提高性能// 這里排除了 node_modules 文件夾的監聽// 但是這在應對需要 npm install 一些新的 module 的時候,就需要重啟服務ignored: /node_modules/,// 是否開始輪詢,有的時候文件已經更改了但是卻沒有被監聽到,這時候就可以開始輪詢// 但是比較消耗性能,選擇關閉poll: devConfig.poll}},plugins: [// 這可以創建一個在編譯過程中的全局變量// 因為這個插件直接執行文本替換,給定的值必須包含字符串本身內的實際引號 --- by webpack// 所以需要這么用// "process.env": JSON.stringify('development')// 或者// "process.env": '"development"'new webpack.DefinePlugin({"process.env": require("../config/dev.env")}),// 開啟大名鼎鼎的熱更新插件new webpack.HotModuleReplacementPlugin(),// 使用大名鼎鼎(詞窮)的 html-webpack-plugin 模板插件new HtmlWebpackPlugin({// 輸出的 html 文件的名字filename: "index.html",// 使用的 html 模板名字template: "index.html",// 是否要插入 weback 打包好的 bundle.js 文件inject: true})] })build/build-server.js 配置詳解
// 更友好的提示插件 var FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin"); // 獲取一個可用的 port 的插件 var portfinder = require("portfinder"); var devWebpackConfig = require("./webpack.dev.conf");// 導出一個 promise 函數,這可以讓 wepback 接受一個異步加載的配置 // 并在 resolve 的時候運行 這個配置 // 比如這里我就用到了 portfinder 和 friendly-errors-webpack-plugin module.exports = new Promise((resolve,reject) => {// 設置插件的初始搜尋端口號portfinder.basePort = devWebpackConfig.devServer.portportfinder.getPort((err,port) => {if (err) reject(err)else {// 這里就利用 portfinder 得到了可以使用的端口devWebpackConfig.devServer.port = portdevWebpackConfig.plugins.push(new FriendlyErrorsPlugin({// 清除控制臺原有的信息clearConsole: true,// 打包成功之后在控制臺給予開發者的提示compilationSuccessInfo: {messages: [`開發環境啟動成功,項目運行在: http://${devWebpackConfig.devServer.host}:${port}`]},// 打包發生錯誤的時候onErrors: () => { console.log("打包失敗") }}))resolve(devWebpackConfig)}}) })編譯出錯了?看看這里
如果你發現直接在控制臺執行 webpack 報錯了,但是你確實執行了 npm install,那是因為你沒有安裝全局的 webpack。-
可以執行 .\node_modules\.bin\webpack --config webpack.config.js
- 調用該項目 node_modules 下的 webpack
-
使用 package.json 配置讓 npm 去找該項目中的 webpack
- package.json > scripts.build: webapck
這個錯誤會發生在你使用的插件沒有針對 webpack 4.x 升級。
這個時候只能去 github 提 issue 或者換一個 plugin 了。
后語
希望自己所做的一些微小的事情可以幫助大家在漫漫前端路中更上一層樓,另外,周末了不要太沉迷于敲代碼,多出去走走,散散步,運動運動,給自己的一周充實的大腦放個空。
如果大家覺得我哪里寫的不對,請不要猶豫,直接 diss 我 =3=
代碼如人生,我甘之如飴。
我在這里 gayhub@jsjzh 歡迎來找我玩兒
向前看就是未來,向后看就是過去,從中取一段下來就是故事,而這只不過是那樣的故事中很小的一部分而已。--- 灰色的果實大綱
-
webpack 4.x 的那些新玩意兒(DONE)
- mode
- optimization
-
webpack 4.x 基礎版開發環境詳細配置(DONE)
- package.json 中的 devDependencies
- package.json 中的 scripts
- build/webpack.base.conf.js 配置詳解
- build/webpack.dev.conf.js 配置詳解
- build/build-server.js 配置詳解
-
webpack 4.x 升級版開發環境詳細配置(TODO)[分篇]
- 利用 babel 轉換 ES6 語法
- 將 img 轉為 dataURL
- 打包 css
- 使用 vue-loader 或其他 loader 來完成更多
- 自己動手開發一個 webpack-plugin
- webpack 4.x 生產環境詳細配置(TODO)[分篇]
-
webpack 配置優化(TODO)[分篇]
- 打包速度優化
- 打包體積優化
總結
以上是生活随笔為你收集整理的一份比较详细的 webpack 4.x 手工配置基础开发环境 附源码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中文字符编码问题
- 下一篇: springboot项目启动优化