Anikyu 是由本人所封裝的一個補間動畫庫,基於JavaScript,能夠爲一個指定對象中的數值建立連續補間動畫。html
Anikyu 源於我平常所寫的一個demo —— 使用JavaScript實現動畫。代碼參考Tween.js的功能進行編寫,緩動函數來自ECharts。前端
Anikyu源代碼倉庫:anikyuvue
畢業後我來了北京。到如今做爲正式員工(2020年4月),我去過兩個公司,都是初創公司,用的技術棧基本都是Vue.js這一套,經過Vue CLI工具便可搭建一個腳手架(空白項目/項目模板),不用任何配置,在初始化事後,腳手架就能夠被啓動了,而後咱們能夠在此基礎上進行開發。node
vue init webpack
以後咱們進入項目目錄,能夠看到以下的文件結構:webpack
事實上,咱們在此關心的內容並很少,僅僅是瞭解一下目錄結構,以及該項目使用到了哪些依賴包。git
參考自vuejs-templates webpackgithub
package.json包含有當前項目的信息。web
由此咱們能夠了解到,咱們使用Vue CLI工具建立的項目:vue-router
在開發環境下須要的包不少(主要是和前端工程化相關的內容),大體概括一下包括幾個大類:shell
注:在最終打出來的生產環境包中僅包含運行依賴項,不會包含開發依賴項。
上面咱們所看的是Vue腳手架初始項目的依賴,使用腳手架靠發的最終產品實質上是一個面向最終用戶、基於Vue的項目,而咱們的目標是構建一個面向開發者的JavaScript的庫。
事實上,咱們開發本身的庫並不用像上面的腳手架同樣須要不少依賴,準確來講其實能夠沒必要任何開發依賴或是運行依賴。咱們徹底能夠不借助任何前端工程化工具,手寫代碼,直接發佈。惟一的問題是代碼可能會稍顯冗餘,或不太嚴謹,或者無論遇到什麼問題都得手動改代碼。
因爲前端工程化是趨勢,本文的目的也主要是學習這些工程化工具。所以,藉助上文中咱們所說起的一些工具:
咱們就能夠構建一個無需任何運行依賴項便可運行的庫。
既然有了對Vue腳手架初始項目文件結構及其依賴項的大體瞭解,咱們是否是就能夠依葫蘆畫瓢,來實現一個本身的庫呢?
這裏,以我以前所寫的Anikyu這個庫爲例來進行介紹。
cd 到將要用於存儲項目的空目錄
使用命令
npm init
填寫一些信息,生成一個package.json
package.json 文件的所有內容已經展示在命令行窗口中,其中包含有在上文沒有說起的一些字段:
import Anikyu from 'anikyu'
)這樣咱們就建立了一個空白項目。
若是咱們不須要使用工程化工具,只需在當前目錄下建立一個index.js文件(對於package.js的入口文件),而後將代碼寫在其中便可。
與此同時,別忘了在項目文件夾裏初始化一個Git倉庫,以確保項目文件出現問題時能夠從倉庫中找回。
能夠將下文說起的相關開發依賴複製到package.json中devDependencies字段下,以後運行npm i
來直接安裝;或者在命令行中手動運行 npm i --save-dev
+依賴名稱 進行安裝。(因爲在中國直接訪問npm的速度很慢,所以這裏使用了cnpm)
"eslint": "^6.8.0"
ESLint 相關依賴以及配置能夠先全局安裝ESLint,而後進入項目文件夾,經過eslint --init
來初始化。
下圖是初始化結束後發生的相關變化。
"eslint-plugin-import": "^2.20.1", "eslint-plugin-node": "^11.0.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1"
若初始化配置的時候選擇了相關內容,同時也會安裝相關依賴(此處暫未了解,今天看項目的時候發現多了這四個依賴,建議先別複製)
"webpack": "^4.41.5", "webpack-cli": "^3.3.10", "babel-loader": "^8.0.6", "@purtuga/esm-webpack-plugin": "^1.2.1", "clean-webpack-plugin": "^3.0.0"
Webpack的核心;不知爲什麼彷佛兩個都須要安裝,不安裝其中一個會報錯?
用於在Webpack中對js文件使用Babel進行處理
用於將庫打包爲符合ES Module的包
打包以前將打包目標文件夾(/dist)進行清空
"@babel/cli": "^7.8.3", "@babel/core": "^7.8.3", "@babel/polyfill": "^7.8.3", "@babel/preset-env": "^7.8.3"
(暫未了解)
經過上文咱們對Vue CLI腳手架的瞭解,咱們也能夠在咱們的庫中規劃出文件結構。
Anikyu是這樣規劃的:
src/ - 寫Anikyu代碼的地方
polyfill/ - polyfill相關代碼
Anikyu庫代碼使用ES6語法來進行組織,例如引入(import ... from ...)、導出(export ...)、類(class)。
因爲Anikyu核心代碼以前已經寫好(我這裏就再也不從頭寫一遍了),所以咱們能夠將項目中src目錄拷貝到新項目根目錄下。
同時也修改一下package.json中的入口文件爲src/anikyu.js。此時這就是一個未進行打包的、由不少零散文件所組成的庫。若是你的瀏覽器支持運行ES Module,那你將可以在瀏覽器中直接運行這個庫。
執行器是Anikyu計算補間的核心,目標對象中值的計算、改變,以及事件的觸發也由執行器來進行。
緩動函數來自ECharts中的相關示例。
Anikyu是一個動畫對象,那對於動畫狀態的監聽(例如監聽動畫幀的請求、動畫的結束)使用和事件相相似的機制會更好一些。
Anikyu類基於EventDoer類,繼承關係如圖所示:
EventDoer相似瀏覽器中自帶的EventTarget對象,能夠爲Anikyu對象添加事件監聽。當Anikyu示例的某一動畫階段正在請求幀或是播放完成的時候,可以觸發相關事件監聽函數。
Anikyu類則用於控制動畫的播放過程,包括暫停、繼續、廢棄等等。
包含了一些經常使用工具,如計算CSS實際值、事件觸發、生成範圍內隨機數、數值限制、時間獲取。
當前僅包含了requestAnimationFrame的polyfill,以兼容IE9瀏覽器。
該文件是Anikyu的出口,用於進行混入polyfill等操做。
若是你早前對Webpack進行過全局安裝(即只需在運行框/cmd.exe中輸入webpack不會報找不到命令),那在這一步驟中,你只需在命令行中輸入:
webpack ./src/anikyu.js
便可完成打包,打包好的文件默認保存在dist目錄下,文件名爲main.js。
經過這種方式打包,咱們發現如下幾個問題:
所以,咱們還須要對Webpack進行深刻配置。
( 參考[Webpack官網 - Authoring Libraries
](https://webpack.js.org/guides... )
此時,咱們在根目錄建立一個webpack.config.js,在其中寫入Webpack配置。
這裏的module.exports
能夠接收一個配置對象(只打包一個文件),也能夠接收由多個相似的配置對象組成的數組(打包多個文件)。這裏咱們建立Anikyu 一種版本的兩個文件 —— 通過壓縮的文件(anikyu.min.js)和未經壓縮的文件(anikyu.js)。兩個文件都符合umd規範,即可以在不支持ES Module的瀏覽器中直接運行,區別僅在於代碼是否被壓縮。
咱們看一看配置對象,以下是未壓縮的UMD版本的配置。
{ entry: './src/anikyu.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'anikyu.js', library: 'Anikyu', libraryTarget: 'umd', libraryExport: 'default', globalObject: 'this' }, mode: 'production', optimization:{ minimize: false } }
output - 輸出配置
optimization - 打包優化
以後咱們在根目錄下,不帶參數直接執行webpack
命令,文件便可開始打包。
上一步中打的包符合umd規範,可以在瀏覽器中經過傳統的script標籤進行引入。但根據個人觀察,不少類庫(如Vue.js、Three.js)都提供了支持ES Module的包,事實上這彷佛也正在成爲一種趨勢。通過本人各類百度,貌似讓Webpack打出ES Module包的方法是引入EsmWebpackPlugin
擴展(來自@purtuga/esm-webpack-plugin包)。
咱們將該擴展引入到webpack.config.js中
在plugins字段中引入,libraryTarget改成var。以後咱們再進行打包,便可打包出ES Module包,實際測試,一切正常。
在以前安裝依賴的過程當中,咱們已經安裝過了babel-loader
,和其它各類各樣的loader同樣,它處理的是js文件(雖然Webpack原生支持處理js,但相關不兼容老舊瀏覽器的代碼並無通過轉譯過程)。
在webpack.config.js中的module字段裏添加rule,表示趕上js文件時就使用babel進行處理。
我認爲,在瀏覽器環境下,原生支持ES Module的瀏覽器必然也支持Anikyu中所使用的相關ES6特性,所以ES Module包我沒有使用Babel,僅對umd包使用Babel。
這是Anikyu的配置,但對於其具體配置詳情本人目前暫無瞭解。
請參閱 Config Files · Babel 。
{ "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage", "targets": { "browsers": ["last 2 versions", "ie >= 9"] } } ] ] }
在配置完成後,咱們能夠從新運行webpack進行打包,此時Babel就能夠對不兼容老舊瀏覽器的代碼進行轉譯,使得庫可供不支持ES6等特性的瀏覽器使用。
行文至此,Anikyu庫的開發、打包實際上已經能夠告一段落,但開發過程當中有的地方還能夠繼續優化,例如代碼風格可能還不夠規範、每次運行打包都要輸入webpack不太方便。
那接下來的步驟咱們就對這些細節進行優化。
上面的步驟中咱們已經安裝好了ESLint,生成了.eslintrc.js這個配置文件,其中的配置都是在執行初始化ESLint命令後根據你的選擇所生成的,此時ESLint規則便已經生效。
我在該文件中的「rules」加入了額外的一些規則,以符合我本身寫代碼的習慣。
"rules": { "indent": [ "error", "tab" ], "linebreak-style": [ "error", "windows" ], "quotes": [ "error", "single" ], "semi": [ "error", "always" ], "space-before-function-paren": 1, "space-infix-ops": 1, "spaced-comment": 1 }
若有文件無需被ESLint檢查,可在.eslintignore裏設置忽略。
在咱們平常開發項目過程當中,例如咱們要打包一個項目,通常會執行 npm run build
,而不是手動執行webpack
。要對此進行配置,咱們須要修改package.json中的script。
{ "test": "echo \"Error: no test specified\" && exit 0", "lint": "eslint src --ext js", "build": "webpack-cli" }
在這裏,咱們添加了lint和build兩個腳本,原有的test腳本因爲我不會配置,因此先讓它 return 0
。
到此,Anikyu庫的開發已經結束,假設如今通過測試,一切運行正常,咱們就能夠對包進行發佈。
npm login
,輸入登陸憑據來登陸npm publish
,便可將包發佈到NPM(尷尬了,剛剛不慎把這裏的demo版本發佈出去了,原本當前線上版本是0.2.2,這裏初始化之後默認版本是1.0.0,忘改了;不過還好我及時用 npm unpublish --force
撤回了剛剛的發佈)
今後,世界各地的人將可以經過npm install anikyu --save
來安裝Anikyu依賴。
我想起啥的時候就寫些啥吧。。。
早期開始作這個庫的時候,我試過直接在配置中傳入函數做爲參數,例如:
new Anikyu({ onAnimate: function(){...}, onFinish: function(){...} })
但這樣作存在的問題是,若是須要在事件被觸發後執行多個函數,這種方式不是很靈活。
正如好久之前在DOM文檔裏寫相關事件處理函數:
window.onload = function (event){ ... }
所以我嘗試讓Anikyu直接繼承瀏覽器自帶的EventTarget對象(該對象提供了咱們所熟知的.addEventListener等方法)。在不一樣瀏覽器上進行測試後,發現任何版本的IE瀏覽器都沒法經過 new EventTarget()
的方式來調用。在繼續測試、查閱文檔過程當中,發現EventTarget類並不可以支持Anikyu所需的全部API。
最終我編寫、模擬了一個和EventTarget類類似的EventDoer類,由Anikyu類繼承。
在Anikyu實例上可這樣調用:
let ani = new Anikyu(...) ani.addEventListener('animate',function(e){ ... })
參考自EventTarget - Web APIs | MDN
前期沒作過深刻了解,只是發現Webpack用途普遍(平常項目以及招聘信息等不少地方都提到這個,順便也學一下),因而就嘗試使用Webpack來進行打包。但Webpack彷佛有個問題,在IE8下,某個地方會提示沒法使用Object.defineProperty方法(可能和Vue.js不支持IE8是同一個緣由),致使報錯。但我本身寫的代碼裏彷佛沒用到Object.defineProperty方法,定眼一看,代碼彷佛來自於Webpack(後來在官網發現Webpack的確只可以兼容到IE9),遂考慮更換一個打包工具。
到後面瞄了一下Three.js、Vue.js和ECharts的打包工具,用的都是Rollup。在某個分支裏我也對其進行了配置,但問題就在於:
最終,遂暫時棄療Rollup。
歷時兩天,整篇文章終於寫完了。這大概就是從0到1搭建一個前端工程化項目的過程吧。不過本人目前仍是處於很菜的狀態,不是很肯定上文的相關表達有沒有很準確、很通俗易懂。若是你對Anikyu這個庫很中意,不妨拿來用一用吧。發現問題,歡迎提issue。
Anikyu是一個面向本人興趣編程的項目,而不是面向公司KPI編程的項目。