摘要:官方推薦不寫重復的配置,即把本地和生產環境共用的配置放到一個文件,然后通過進行合并我們可以看到,通過插件,將共用配置和開發的配置進行合并定義了全局變量這個插件是為了在我們允許后,自動打開頁面,避免每次都手動打開。
之前只知道webpack很強大,但是一直沒有深入學習過,這次從頭看了一下教程,然后從0開始搭建了一個多入口網站的開發腳手架,期間遇到過很多問題,所以有心整理一下,希望能給大家一點幫助。
多HTML網站使用webpack的必要性假如我們接到這樣一個任務,開發一個簡單的官網,比如只有十幾個html頁面。項目很簡單,我們沒有必要使用什么大型框架,但是如果只是傳統的寫幾個html、js和css,肯定會遇到這幾個問題:
網站導航和底部通欄是每個頁面都共有的,如何實現復用?如果不復用,那么有改動的時候就要改n個頁面,未免太傻
如何在更改后強制清空用戶緩存?我們不可能要求用戶手動去清除瀏覽器緩存,那樣太傻
我想使用ES6進行js的開發,如何解決瀏覽器兼容性問題?
我想使用less進行css樣式開發,如何轉換?
可以看出,沒有自動化打包工具的加入,這些問題我們是很難解決的,因此使用webpack勢在必行。
要實現的目標看到這里,可能有的同學就急了,別廢話,感覺進入正題吧,不!我們先定目標!無論做什么事情,都要先定目標,而不是干到哪里算哪里,這樣是不會有大的提升的,正是在邁向目標的路上克服各種問題,我們才有進步,在進行這個腳手架搭建之前,我希望它是這樣的
能夠打包成多個html文件和js文件,即支持多入口
文件名稱都要帶上hash值,解決緩存問題
能夠復用網站的頭部導航欄和底部通欄
通過采用less進行樣式的編寫
能夠支持ES6開發
用起來要方便,增加頁面不需要手動去更改webpack的入口設置,希望能夠根據目錄下的文件自動配置
不希望通過js動態插入css樣式,這樣會造成頁面閃爍,希望html中直接引入css地址,就像平時開發那樣
能夠實時看到開發的效果
build能夠對代碼進行壓縮
好了,目標定了,開工
目錄結構別急,我們先來捋一捋目錄,別著急寫代碼,一個好的目錄,能讓我們思路清晰,我的目錄結構如下
+ config //環境變量配置文件,開發模式和生產模式使用不同的環境變量,比如接口地址,開發環境用的接口域名是http://a.com,生產環境使用的是http://b.com - dev.env.js //本地開發變量 - prod.env.js //生產環境變量 + src + css //自己的less組件或者第三方css庫 + component //自己組件的less + lib //第三方的css庫,比如bootstrap + html //html代碼,主要是一些模板,如頭部導航,底部通欄,側邊欄 + tpl //模板文件 + img //圖片文件 + js //自己的js組件庫或者第三方js庫 + mod //自己的js組件放這里 + lib //第三方js庫 + page //頁面文件 + index //這個根據自己情況設置,有的頁面相關性強,可以放到一個文件夾下,比如一個user文件夾,可以放個人中心的所有頁面 - index.html //每個頁面都要有一個html - index.js //每個頁面都要有一個js,名稱和html的名稱保持一致 - index.less //每個頁面都要有一個同名less文件 + test - test.html - test.js - test.less + webpack //webpack的配置文件 - dev-server.js //開發服務設置,可以通過localhost訪問頁面,頁面的實時編譯 - webpack.common.js //開發環境和生產環境通用配置 - webpack.dev.js //開發環境特有的配置 - webpack.prod.js //生產環境特有的配置
首先是config目錄,目前我主要放一些環境變量,就是開發環境和生產環境所不同的變量,比如接口地址,我們開發的時候,用本地的api接口地址,而打包的時候,要換成生產環境api地址。
webpack目錄存放webpack的配置文件,其中開發和生產通用配置 放到webpack.common.js中,開發特有配置放到webpack.dev.js中,生產特有配置放到webpack.prod.js中。
src是我們開發的主目錄,其中page目錄放置我們的頁面文件,這里可能和平時有所不同,我把每個頁面用到的html、js和less文件放到了一起,有的同學可能把所有html放到一個目錄下,js放到一個目錄下,但是這樣存在一個問題,每次改動頁面,都要去翻目錄,非常的不方便,我們應該把這種高度相關的文件放到一起,而提取的各種css組件或js組件可以和頁面分開放置。
github地址:https://github.com/501351981/...
多入口配置webpack支持多入口,即給定多個入口js文件,可以輸出多個js文件,那么html怎么辦呢?我希望開發過程是這樣的,我在html中設置標題、SEO等信息,編寫HTML內容代碼,webpack把相關的js文件自動插入到html底部就行,可以的,這需要用到html-webpack-plugin 插件,可以通過調用html模板文件打包最終html。
安裝html-webpack-plugin
npm install --save-dev html-webpack-plugin
webpack.common.js中多入口配置
const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports={ entry:[ index:"../src/page/index/index.js", test:"../src/page/test/test.js" ], output: { filename: "[name].[hash].js", //輸出名稱后面跟哈希值,解決緩存問題 path: path.resolve(__dirname,"../dist") }, .... plugins: [ new HtmlWebpackPlugin({ filename: "index.html", template: "../src/page/index/index.html", chunks: ["index"], }) new HtmlWebpackPlugin({ filename: "test.html", template: "../src/page/test/test.html", chunks: ["test"], }) ] }
這樣設置存在一個問題,每次新增一個頁面,我就要到這里添加一下,未免很麻煩,我們其實可以通過讀取 src/page下的js文件,自動加入入口配置;讀取 src/page下的所有html文件,自動調用new HtmlWebpackPlugin進行實例化。
讀取目錄下所有文件名,我們需要引入glob,先安裝
npm install --save-dev glob
改進后的配置
const glob = require("glob") const CleanWebpackPlugin = require("clean-webpack-plugin"); //多入口js的配置,讀取src/page下所有的js文件 function entries() { let jsDir = path.resolve(__dirname, "../src/page") let entryFiles = glob.sync(jsDir + "/**/*.js") let map = {}; for (let i = 0; i < entryFiles.length; i++) { let filePath = entryFiles[i]; let filename = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf(".")); map[filename] = filePath; } return map; } //讀取多個html模板,進行插件實例化 function newHtmlWebpackPlugins(){ let jsDir = path.resolve(__dirname, "../src/page") let htmls = glob.sync(jsDir + "/**/*.html") let plugins=[] for (let i = 0; i < htmls.length; i++) { let filePath = htmls[i]; let filename_no_extension = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf(".")); let filename=filename_no_extension.concat(".html") plugins.push(new HtmlWebpackPlugin({ filename: filename, template: filePath, chunks: [filename_no_extension], })) } return plugins } module.exports={ entry:entries(), output: { filename: "[name].[hash].js", path: path.resolve(__dirname,"../dist") }, .... plugins: [ ...newHtmlWebpackPlugins() ] }
好了,現在新增頁面不需要更改webpack配置了,只需要重新運行一下 npm run start即可
共有頭部和底部的復用頭部導航和底部通欄我們各個頁面都是一樣的,因此需要引入,那么html中怎么引入另一個html呢,這需要用到raw-loader 或 html-withimg-loader
安裝raw-loader,raw-loader可以加載文件原始內容(utf-8格式)
npm install --save-dev raw-loader
//目錄結構 + src + html + tpl - navbar.html //共用的頭部導航 - footer.html //共用的底部導航 + page //頁面文件 + index - index.html + test - test.html
我們在index.html中可以這么引用導航和底部通欄
<%=require("raw-loader!../../html/tpl/navbar.html")%><%=require("raw-loader!../../html/tpl/footer.html")%>首頁的內容在這里
最初我在查找解決方案的時候,看到文章推薦使用raw-loader,但是發現這樣存在一個問題,就是導航中無法引用本地的圖片,比如導航中引用一個logo圖片,是找不到的,因為我們打包的時候也會對圖片進行處理,后面添加hash值,直接寫圖片路徑是不行的,后來我改用 html-withimg-loader解決了
安裝html-withimg-loader,顧名思義,這個插件可以加載帶有圖片的html
npm install --save-dev html-withimg-loader
<%=require("html-withimg-loader!../../html/tpl/navbar.html")%><%=require("html-withimg-loader!../../html/tpl/footer.html")%>首頁的內容在這里
順便提一句,html中引用圖片地址是需要這樣寫的,需要通過require才行,簡單的填寫圖片地址是不行的
支持ES6編寫js相信大家現在都已經學過ES6了,可是鑒于瀏覽器的兼容性,還沒法隨心所欲的用,需要插件支持,我們首先安裝
npm install --save-dev babel-loader babel-core babel-preset-env
添加webpack配置
webpack.common.js,我們只對src目錄下的js進行轉換
{ test: /.js$/, use: { loader: "babel-loader" }, include: path.resolve(__dirname,"../src") },
同時在項目目錄下添加一個名為.babelrc的文件,對babel進行設置,支持占有率大于1%的瀏覽器的最近2個版本
{ "presets": [ ["env",{ "targets": { "browsers": ["> 1%", "last 2 versions"] } }] ], }
babel只是將ES6語法轉為ES5的語法,比如箭頭函數轉為function(){},但是對一些ES6特有的功能沒有轉換,比如new Map(),打包之后還是new Map(),我們還需要再安裝一個插件,完成這個轉換工作。
npm install --save-dev babel-plugin-transform-runtime
更改.babelrc文件
{ "presets": [ ["env",{ "targets": { "browsers": ["> 1%", "last 2 versions"] } }] ], "plugins": ["transform-runtime"] //引入插件 }
現在可以放心大膽的使用ES6了
使用Less編寫樣式首先還是安裝相關插件
npm install --save-dev less less-loader css-loader style-loader
webpack.common.js配置
{ test: /.css$/, use:["style-loader","css-loader","less-loader"] },
在index.js文件中,我們就可以這樣引入less文件了
import "./index.less"
打包之后,運行html頁面,index.js會動態把css樣式插入到html頁面,這樣會造成一個問題,剛加載html的時候是一個樣式,js插入css樣式后是另一個樣式,造成頁面閃爍一下,體驗不好(技術也要追求用戶體驗啊,不光是產品經理的事)。這有兩個解決方案吧,第一個就是在JS未加載完成之前,顯示一個loading動畫,把整個頁面遮蓋住,第二個就是把css文件路徑打包進html中,不要通過js動態添加,我選用的第二個方案。
我們要把less文件打包到一個css文件中,需要用到插件extract-text-webpack-plugin
npm install --save-dev extract-text-webpack-plugin
webpack.common.js
const ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports={ rules: [ { test: /.less$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader!less-loader" }) }, ] } plugins: [ new ExtractTextPlugin("[name].[hash:8].css"), ]
這樣打包之后的html中會引入css文件,類似這樣
webpack配置
實際在我從0開始搭建的過程中,是先進行webpack這塊的配置的,之所以放到最后是不想影響主干內容,下面我們也簡單介紹一下我的webpack配置。
webpack官方推薦不寫重復的配置,即把本地和生產環境共用的配置放到一個文件,然后通過merge進行合并
webpack.dev.js
const webpack = require("webpack"); const merge = require("webpack-merge"); const common = require("./webpack.common"); var OpenBrowserPlugin = require("open-browser-webpack-plugin"); const env=require("../config/dev.env") module.exports=merge(common,{ mode:"development", devtool: "inline-source-map", plugins:[ new webpack.DefinePlugin({ "process.env": env }), new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin(), new OpenBrowserPlugin({ url: "http://localhost:5000" }) ], })
我們可以看到,通過webpack-merge插件,將共用配置webpack.common.js和開發的配置進行合并
new webpack.DefinePlugin({ "process.env": env }),
DefinePlugin定義了全局變量process.env
new OpenBrowserPlugin({ url: "http://localhost:5000" })
這個插件是為了在我們允許npm run start后,自動打開頁面http://localhost:5000,避免每次都手動打開。
webpack-dev-server 為我們提供了一個簡單的 web 服務器,并且能夠實時重新加載,讓我們可以實時看到開發結果,關于web服務器的配置,我放到了dev-server.js中
const webpackDevServer = require("webpack-dev-server"); const webpack = require("webpack"); const config = require("./webpack.dev"); const options = { contentBase: "./dist", hot: true, host: "localhost", }; webpackDevServer.addDevServerEntrypoints(config, options); const compiler = webpack(config); const server = new webpackDevServer(compiler, options); server.listen(5000, "localhost", () => { console.log("dev server listening on port 5000"); });
在package.json中,我們添加兩個腳本
"scripts": { "start": "node webpack/dev-server.js", "build": "npx webpack --config webpack/webpack.prod.js", },
這樣我們就可以在命令行輸入兩個命令
npm run start :進入開發模式
npm run build:打包生產環境代碼
好了,基本上把我做的這個腳手架介紹完了,實際要理解還需要自己去試,看是一回事,做出來又是另一回事,給別人講明白那就更不容易了,前端路漫漫,大家努力吧。
github地址:https://github.com/501351981/...
這個腳手架還不完善,不過基本夠用了,后面我還會再做幾個腳手架,比如結合vue進行多頁面開發或移動端H5開發,有興趣可以持續關注。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/53294.html
摘要:官方推薦不寫重復的配置,即把本地和生產環境共用的配置放到一個文件,然后通過進行合并我們可以看到,通過插件,將共用配置和開發的配置進行合并定義了全局變量這個插件是為了在我們允許后,自動打開頁面,避免每次都手動打開。 之前只知道webpack很強大,但是一直沒有深入學習過,這次從頭看了一下教程,然后從0開始搭建了一個多入口網站的開發腳手架,期間遇到過很多問題,所以有心整理一下,希望能給大家...
摘要:開箱即用的多頁面腳手架基于模塊化開發可復用的現代化網站感興趣的朋友,請點個及時關注項目更新請點個項目請提特性支持前后端分離開發配置完整的打包方案支持本地開發熱更新集成代碼風格校驗支持編寫源碼,編譯生成生產代碼內置開發環境,自動加樣式前綴自 Webpack-seed 開箱即用的多頁面腳手架, 基于webpack4.2x babel7.1x模塊化開發可復用的現代化網站(Without Vu...
摘要:側邊欄我們先圖解一下側邊欄的結構整個側邊欄主從上到下按區塊分別放置了賬號和若干功能項分割線的列表,很容易想到使用布局控件。賬號信息區域中有賬號頭像粉絲頭像賬號文字信息和背景圖,這塊我們可以使用控件庫的控件實現。 經過2周的學習,看過筆記1-8的小伙伴們已經有不少開始自己寫APP了,我也按耐不住這股熱情,想要自己開發個APP玩玩,so,從本篇起,仿造一個APP,項目從0開始,每篇增加一些...
摘要:五一之前就想寫一篇關于的文章結果朋友結婚就不了了之了。記得最后一定要看注意事項更新倉庫介紹官網類似一個極簡的靜態網站生成器用來寫技術文檔不能在爽。當然搭建成博客也不成問題。構建與自動部署用的或者的都可以也可以搭建在自己的服務器上。 五一之前就想寫一篇關于Vuepress的文章,結果朋友結婚就不了了之了。記得最后一定要看注意事項! 更新:coding倉庫:https://git.dev...
摘要:故九萬里,則風斯在下矣,而后乃今培風背負青天,而莫之夭閼者,而后乃今將圖南。這里是文件的內容部分最后更新時間最后更新時間默認不開啟,它是基于提交的時間戳,所以我們的靜態站點是需要通過的倉庫進行管理的,并且它是按的時間來計算的。VuePress(0.x版本) 本blog配套了一個基于 VuePress 的一個簡單的配置案例,此配置案例包含了本blog絕大部分配置案例,更多詳情請移步這里VueP...
閱讀 3406·2021-11-25 09:43
閱讀 3464·2021-11-19 09:40
閱讀 2464·2021-10-14 09:48
閱讀 1283·2021-09-09 11:39
閱讀 1920·2019-08-30 15:54
閱讀 2821·2019-08-30 15:44
閱讀 1994·2019-08-29 13:12
閱讀 1543·2019-08-29 12:59