摘要:那我們有沒(méi)有辦法不刷新頁(yè)面又能看到代碼的更新呢其實(shí)很簡(jiǎn)單,因?yàn)橐呀?jīng)內(nèi)置了這樣的功能,我們只要配置下的注意到上面的代碼,我們?cè)黾恿?,讓開(kāi)發(fā)環(huán)境有了熱更新的能力。
作者:Nicolas (滬江Web前端)
本文為原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明作者及出處
本文的 webpack 代碼示例根據(jù) webpack 2.7.0 編寫(xiě),并在 Mac 上正常運(yùn)行。
去年一篇《在 2016 年學(xué) JavaScript 是一種什么樣的體驗(yàn)?》嚇壞了很多想要入行新同學(xué)和入行很久的老司機(jī),感覺(jué)一下子前端世界已經(jīng)看不懂了,做個(gè)頁(yè)面要那么麻煩?當(dāng)然如果你只是想要一個(gè)簡(jiǎn)單的靜態(tài)頁(yè)面,這么玩兒就是殺雞用牛刀了。但如果你準(zhǔn)備開(kāi)發(fā)一個(gè) Web App,之后會(huì)不斷的迭代,有一個(gè)舒適的開(kāi)發(fā)環(huán)境是及其重要的,那么底怎么樣的環(huán)境才會(huì)是舒適愉悅的呢?
比如這樣的一個(gè)環(huán)境:資源依賴(lài)可以安裝并模塊化引用、可以使用很酷的 ES6 語(yǔ)法、可以使用 SASS 預(yù)處理器寫(xiě) CSS、代碼可實(shí)時(shí)更新而不用一遍遍的手動(dòng)刷新頁(yè)面,這樣的開(kāi)發(fā)環(huán)境你會(huì)不會(huì)覺(jué)得很爽!好,我們這就來(lái)配置一個(gè)這樣的環(huán)境!
基礎(chǔ)環(huán)境首先,你需要一個(gè) Node.js,然后 NPM 也會(huì)隨著 Node.js 一起裝上。
什么是 NPM ?簡(jiǎn)單的說(shuō) NPM 是用來(lái)下載安裝 Node.js 的第三方工具包的一個(gè)管理器。當(dāng)然,現(xiàn)在也可以安裝瀏覽器中使用的包。提到包管理器,就不得不說(shuō)下 Bower,Bower 之前一直是前端庫(kù)管理工具,一開(kāi)始 NPM 只能發(fā)布和安裝 Node.js 的包,所以 Bower 盛行一時(shí),隨著 CommonJS 的普及,以及 UMD 規(guī)范的出現(xiàn),讓 NPM 安裝前端瀏覽器 js 包成為了可能,隨著 NPM 生態(tài)的成熟,Bower 也就慢慢被人淡忘了~
Node.js 安裝完成后,可以執(zhí)行以下命令驗(yàn)證安裝是否成功:
$ node -v v6.11.0 $ npm -v 3.10.10
別急,Node.js 的部分還沒(méi)完,國(guó)內(nèi)通過(guò) NPM 的官方源安裝依賴(lài)好像很慢,動(dòng)不動(dòng)就要等上半天,如何解決?我們可以裝一個(gè) nrm!nrm 是 npm registry 管理工具,可以自由切換 npm registry,然后命令行使用時(shí)依然是 npm ,國(guó)內(nèi)有很多 npm 的鏡像,比如淘寶的 cnpm ,然而很多公司都架設(shè)了自己的私庫(kù)。什么是私庫(kù)?私庫(kù)就是只能在公司內(nèi)網(wǎng)訪(fǎng)問(wèn),不能發(fā)布到 npm 共享平臺(tái)的 npm 包,比如我們大公司私庫(kù)的 registry 的名稱(chēng)就是 hnpm。不細(xì)說(shuō)了,我們先裝一個(gè)試試:
$ npm install -g nrm
然后根據(jù)官方教程我們先切一個(gè)國(guó)內(nèi)的 registry,比如大淘寶的:
$ nrm use cnpm
然后用 NPM 隨便安裝個(gè)什么,看看速度如何?是不是很快^_^
等等,Node.js 還有。有的開(kāi)發(fā)依賴(lài)包是有 Node.js 版本依賴(lài)的,我們知道 Node.js 不同大版本的功能還是差別很大的,但我們又不會(huì)一遍遍的卸載安裝吧?感覺(jué)好蠢!好吧,我們當(dāng)然可以裝一個(gè)nvm,nvm?好像和 nrm 很像!nvm 是 Node.js 的版本管理工具,可以在多個(gè)終端切換和運(yùn)行不同的 Node.js 版本,可以到這里參考具體的安裝教程。不過(guò) nvm 在 windows 下不能使用,沒(méi)關(guān)系,這里還有幾個(gè)替代工具:nvm-window,gnvm 供你選擇。
同樣,我們執(zhí)行下命令驗(yàn)證安裝成果:
$ nvm --version 0.33.0項(xiàng)目初始化
有了上面的工具我們就可以開(kāi)始創(chuàng)建一個(gè)項(xiàng)目了,我們執(zhí)行以下命令來(lái)開(kāi)始一個(gè)項(xiàng)目:
mkdir my-app cd my-app npm init
執(zhí)行 npm init 后你會(huì)看到你需要輸入項(xiàng)目的一些信息,完成后回車(chē)確認(rèn),然后npm會(huì)在根目錄下創(chuàng)建一個(gè)叫 package.json 的文件,你之后通過(guò) --save 或者 --save-dev 安裝的依賴(lài)包都會(huì)出現(xiàn)在這個(gè)文件里。
先不管那么多,我們?cè)诟夸浵聞?chuàng)建一個(gè) src 目錄,然后在 src 下創(chuàng)建index.js、index.html……,好吧,你可以按照下面的結(jié)構(gòu)新建文件:
. ├── package.json └── src ├── index.css ├── index.html └── index.js
在以下文件中輸入代碼:
index.js:
var el = document.createElement("div"), text = document.createTextNode("My App"); el.appendChild(text); document.body.appendChild(el);
index.html:
My App
我們要想辦法讓這個(gè)頁(yè)面跑起來(lái),what??? 就這么簡(jiǎn)單?,把js引入 index.html 不就完事兒了嘛?當(dāng)然沒(méi)那么簡(jiǎn)單,我們可是要搞高大上的東西的呢!
哈~跑題了,我們繼續(xù)。
首先我們要裝一個(gè)叫 webpack 的東西,它是一個(gè)模塊打包器,也就是我們俗稱(chēng)的構(gòu)建工具,之前的那些 Grunt,Gulp 也都是構(gòu)建工具,但是這年頭流行 webpack 了!開(kāi)個(gè)玩笑,webpack 的可擴(kuò)展性和可插件化,以及把任何文件都視為模塊的概念得到了前端社區(qū)的一致推崇,而且在打包效率和按需分割文件上都是其他幾個(gè)構(gòu)建工具無(wú)法相比較的,當(dāng)然 webpack 的配置太靈活,官方文檔寫(xiě)的太太太難看懂,也導(dǎo)致了很多初學(xué)者無(wú)從下手。
接下來(lái)我們就來(lái)配下這個(gè)神奇的工具吧。
自動(dòng)構(gòu)建我們先安裝下 webpack:
npm install --save-dev webpack
然后在根目錄下新建一個(gè) webpack.config.js 文件,輸入以下代碼:
let path = require("path"); module.exports = { entry: { app: path.resolve(__dirname, "src", "index.js") }, output: { filename: "[name].js", path: path.resolve(__dirname, "dist") } };
但要想在瀏覽器中訪(fǎng)問(wèn)還得有個(gè)本地服務(wù)器,好在 webpack 都幫我們想到了,我們可以裝一個(gè)webpack-dev-server:
npm install --save-dev webpack-dev-server
我們?cè)?package.json 中增加個(gè) npm scripts:
"scripts": { "start": "webpack-dev-server --port 3003" },
ok!我們執(zhí)行下 npm start,在瀏覽器中訪(fǎng)問(wèn):http://localhost:3003。哎?好像哪里不對(duì)!是的,你得告訴 webpack,你的 bundle(打包后的 js)要插入到哪個(gè) html 模板,前面說(shuō)過(guò),webpack 是插件化的,它把很多功能開(kāi)放給了第三方來(lái)實(shí)現(xiàn),他只是來(lái)負(fù)責(zé)拼裝的,好,現(xiàn)在我們需要安裝一個(gè) html-webpack-plugin 插件:
npm install --save-dev html-webpack-plugin
修改下 webpack-config.js:
let HtmlWebpackPlugin = require("html-webpack-plugin"), path = require("path"); module.exports = { entry: { ... }, ... plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, "src", "index.html") }) ] }
再次執(zhí)行 npm start,頁(yè)面可以正常訪(fǎng)問(wèn)了。
但是,這樣似乎有點(diǎn) low,我們新增一個(gè)文件 utils.js,搞點(diǎn)es6語(yǔ)法:
. ├── package.json └── src ├── index.css ├── index.html ├── index.js +?? └── utils +?? └── utils.js
utils.js:
export function wordsToSentence(...words) { return words.join(" "); }
修改 index.js
+ import { wordsToSentence } from "./utils/utils"; let el = document.createElement("div"), - text = document.createTextNode("My App"); + text = document.createTextNode( + wordsToSentence("Welcome", "to", "my", "app!") + ); el.appendChild(text); document.body.appendChild(el);
刷新頁(yè)面后好像也沒(méi)什么異常(你肯定用了 chrome 吧?。屑?xì)看控制臺(tái)的 source 的 app.js(你的 bundle)的代碼片段:
"use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = wordsToSentence; function wordsToSentence(...words) { return words.join(" "); }
值得注意的是,使用 ES6 時(shí)需要考慮那些沒(méi)有支持 ES6 的舊瀏覽器,雖然在 chrome 或者其他高級(jí)瀏覽器中沒(méi)有出現(xiàn)問(wèn)題,但不能保證在其他瀏覽器中能正常運(yùn)行。為了萬(wàn)無(wú)一失,我們需要將 ES6 轉(zhuǎn)換為 ES5,也就是js代碼轉(zhuǎn)換器,這類(lèi)工具當(dāng)今世界就屬 Babel 最牛逼了:
npm install --save-dev babel-loader babel-core
稍等,裝了 Babel 還沒(méi)法用,還得搞個(gè) presets:
npm install --save-dev babel-preset-env
在根目錄下新建個(gè) .babelrc,輸入配置:
{ "presets": ["env"] }
修改 webpack.config.js,增加 babel 的支持:
... module.exports = { ... module: { rules: [ { test: /.js$/, loader: "babel-loader", include: path.resolve(__dirname, "src") } ] }, ... };
執(zhí)行 npm start,找到控制臺(tái) source 下的 app.js 代碼片段:
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.wordsToSentence = wordsToSentence; function wordsToSentence() { for (var _len = arguments.length, words = Array(_len), _key = 0; _key < _len; _key++) { words[_key] = arguments[_key]; } return words.join(" "); }
已經(jīng)成功轉(zhuǎn)換成 ES5 代碼。但是,目前 ES6 Modules 是由 Babel 來(lái)轉(zhuǎn)的,你可以對(duì)比前后 2 次的代碼片段的模塊輸出部分。現(xiàn)在,webpack 2 已經(jīng)內(nèi) 4 置了 ES6 Modules 的轉(zhuǎn)換,據(jù)說(shuō)效率和性能比 Babel 高!^_^沒(méi)驗(yàn)證過(guò)哦,我們先試試,把 Babel 的模塊轉(zhuǎn)換關(guān)了先:
.babelrc
{ "presets": [ ["env", { "modules": false }] ] }
執(zhí)行 npm start 再次查看輸出后的 app.js 的代碼片段:
-Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.wordsToSentence = wordsToSentence; +/* harmony export (immutable) */ __webpack_exports__["a"] = wordsToSentence; function wordsToSentence() { ... }
模塊輸出方式又回到了使用 Babel 前的代碼。
js 的環(huán)境似乎已經(jīng)準(zhǔn)備就緒,但 css 還沒(méi)上場(chǎng),我們來(lái)修改下 index.css:
#app { color: #57af09; }
同時(shí)將 css 導(dǎo)入 bundle 入口,并修改下 index.js:
import "./index.css"; import { wordsToSentence } from "./utils/utils"; let el = document.createElement("div"), ... el.id = "app"; ...
有了樣式還不行,webpack 還需要相應(yīng)的 loader 來(lái)處理 css 的模塊:
npm i --save-dev style-loader css-loader
修改下 webpack.config.js:
... module.exports = { ... module: { rules: [ ... { test: /.css$/, loader: ["style-loader", "css-loader"], include: path.resolve(__dirname, "src") } ] }, ... };
執(zhí)行 npm start,現(xiàn)在可以看到頁(yè)面已經(jīng)有了樣式。但是,我們說(shuō)過(guò),我們希望使用先進(jìn)的武器:SASS。我們修改下 index.css:
$app-color: #57af09; #app { color: $app-color; }
再修改下文件后綴:
. ├── package.json └── src - ├── index.css + ├── index.scss ...
修改 index.js 的入口:
-import "./index.css"; +import "./index.scss";
由于文件(模塊)類(lèi)型變了,我們還需要一個(gè) SASS 的 webpack loader:
npm install --save-dev sass-loader node-sass
再次修改 webpack.config.js:
... module.exports = { ... module: { rules: [ ... { - test: /.css$/, + test: /.scss$/, - loader: ["style-loader", "css-loader"], + loader: ["style-loader", "css-loader", "sass-loader"], include: path.resolve(__dirname, "src") } ] }, ... };
執(zhí)行 npm start,webpack 編譯沒(méi)有報(bào)錯(cuò),頁(yè)面顯示一切正常!
代碼自動(dòng)更新(熱更新)如果你嘗試修改 index.scss 的樣式,你有沒(méi)注意到一個(gè)問(wèn)題:頁(yè)面會(huì)自動(dòng)刷新。但有時(shí)候我們?cè)陂_(kāi)發(fā)一個(gè)模塊,比如 dialog,刷新會(huì)導(dǎo)致你需要反復(fù)的在頁(yè)面上操作才能看到這個(gè) dialog 的樣式更新。那我們有沒(méi)有辦法不刷新頁(yè)面又能看到代碼的更新呢?
其實(shí)很簡(jiǎn)單,因?yàn)?webpack-dev-server 已經(jīng)內(nèi)置了這樣的功能,我們只要配置下 package.json的 npm scripts:
"scripts": { "start": "webpack-dev-server --hot --inline --port 3003" },
注意到上面的代碼,我們?cè)黾恿?--hot --inline,讓開(kāi)發(fā)環(huán)境有了熱更新的能力。我們重新執(zhí)行 npm start,然后將你的瀏覽器和編輯器并排放置,然后反復(fù)修改 index.scss,你會(huì)看到頁(yè)面不會(huì)刷新,但樣式在自動(dòng)的推送更新,這就是傳說(shuō)中的熱更新。
結(jié)束語(yǔ)到這里,簡(jiǎn)單(簡(jiǎn)陋)的、現(xiàn)代化的前端開(kāi)發(fā)環(huán)境已經(jīng)有了基本的雛形,但是,本篇文章不是webpack 的使用指南,也不是 ES6 的語(yǔ)法教程,盡管如此,還是希望你通過(guò)本篇文章感受到前端開(kāi)發(fā)在工程化領(lǐng)域的發(fā)展帶來(lái)的驚喜。
iKcamp原創(chuàng)新書(shū)《移動(dòng)Web前端高效開(kāi)發(fā)實(shí)戰(zhàn)》已在亞馬遜、京東、當(dāng)當(dāng)開(kāi)售。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85135.html
摘要:前端日?qǐng)?bào)精選如何優(yōu)雅的編寫(xiě)代碼深入理解內(nèi)部機(jī)制專(zhuān)題之函數(shù)組合年月個(gè)有趣的和庫(kù)最經(jīng)典的前端面試題之一,你能答出什么幺蛾子中文翻譯深入理解響應(yīng)式原理掘金譯與和交互掘金箭頭函數(shù)使用禁忌技術(shù)棧耕耘助力美團(tuán)點(diǎn)評(píng)前端進(jìn)階之路前端模塊 2017-09-01 前端日?qǐng)?bào) 精選 如何優(yōu)雅的編寫(xiě) JavaScript 代碼深入理解 Node.js Stream 內(nèi)部機(jī)制JavaScript專(zhuān)題之函數(shù)組合20...
摘要:馬爾代夫之行重頭戲這一年的工作情況這一年,個(gè)人感覺(jué)還是做了不少事情,主要集中在我們公司的前端領(lǐng)域,同時(shí)也給整個(gè)技術(shù)團(tuán)隊(duì)不少的建議,引入了不少新的東西和方式,總結(jié)起來(lái)比較重要的在下面五個(gè)方面。 如果想看技術(shù)相關(guān)的,下拉到后面的重頭戲就是了。 一個(gè)活動(dòng)頁(yè)面 在15年末的時(shí)候,加入到羅輯思維,剛過(guò)來(lái)就接手了一個(gè)微信朋友圈要傳播的活動(dòng)頁(yè)面,效果頁(yè)面大概和當(dāng)時(shí)錘子手機(jī)的活動(dòng)頁(yè)面漂亮的不像實(shí)力派類(lèi)...
摘要:老姚淺談怎么學(xué)鑒于時(shí)不時(shí),有同學(xué)私信問(wèn)我老姚,下同怎么學(xué)前端的問(wèn)題。擼碼聽(tīng)歌,全局控制。 淺析用 js 解析 xml 的方法 由于項(xiàng)目上需要解析 xml,于是各種百度,然后自己總結(jié)了下各個(gè)主流瀏覽器解析 xml 的方法,只能是很淺顯的知道他的用法,但是還沒(méi)有深層次的研究。 裝 X - 建立自己的斗圖網(wǎng)站庫(kù) 之前加過(guò)一個(gè)斗圖群,看到很多經(jīng)典的表情,然后就收藏到了 QQ, 迫于本屌絲開(kāi)不起...
閱讀 1683·2023-04-26 00:30
閱讀 3155·2021-11-25 09:43
閱讀 2884·2021-11-22 14:56
閱讀 3194·2021-11-04 16:15
閱讀 1155·2021-09-07 09:58
閱讀 2028·2019-08-29 13:14
閱讀 3113·2019-08-29 12:55
閱讀 993·2019-08-29 10:57