摘要:那我们有没有办法不刷新页面又能看到代码的更新呢其实很简单,因为已经内置了这样的功能,我们只要配置下的注意到上面的代码,我们增加了,让开发环境有了热更新的能力。
作者:Nicolas (沪江Web前端)
本文为原创文章,转载请注明作者及出处
本文的 webpack 代码示例根据 webpack 2.7.0 编写,并在 Mac 上正常运行。
去年一篇《在 2016 年学 JavaScript 是一种什么样的体验?》吓坏了很多想要入行新同学和入行很久的老司机,感觉一下子前端世界已经看不懂了,做个页面要那么麻烦?当然如果你只是想要一个简单的静态页面,这么玩儿就是杀鸡用牛刀了。但如果你准备开发一个 Web App,之后会不断的迭代,有一个舒适的开发环境是及其重要的,那么底怎么样的环境才会是舒适愉悦的呢?
比如这样的一个环境:资源依赖可以安装并模块化引用、可以使用很酷的 ES6 语法、可以使用 SASS 预处理器写 CSS、代码可实时更新而不用一遍遍的手动刷新页面,这样的开发环境你会不会觉得很爽!好,我们这就来配置一个这样的环境!
基础环境首先,你需要一个 Node.js,然后 NPM 也会随着 Node.js 一起装上。
什么是 NPM ?简单的说 NPM 是用来下载安装 Node.js 的第三方工具包的一个管理器。当然,现在也可以安装浏览器中使用的包。提到包管理器,就不得不说下 Bower,Bower 之前一直是前端库管理工具,一开始 NPM 只能发布和安装 Node.js 的包,所以 Bower 盛行一时,随着 CommonJS 的普及,以及 UMD 规范的出现,让 NPM 安装前端浏览器 js 包成为了可能,随着 NPM 生态的成熟,Bower 也就慢慢被人淡忘了~
Node.js 安装完成后,可以执行以下命令验证安装是否成功:
$ node -v v6.11.0 $ npm -v 3.10.10
别急,Node.js 的部分还没完,国内通过 NPM 的官方源安装依赖好像很慢,动不动就要等上半天,如何解决?我们可以装一个 nrm!nrm 是 npm registry 管理工具,可以自由切换 npm registry,然后命令行使用时依然是 npm ,国内有很多 npm 的镜像,比如淘宝的 cnpm ,然而很多公司都架设了自己的私库。什么是私库?私库就是只能在公司内网访问,不能发布到 npm 共享平台的 npm 包,比如我们大公司私库的 registry 的名称就是 hnpm。不细说了,我们先装一个试试:
$ npm install -g nrm
然后根据官方教程我们先切一个国内的 registry,比如大淘宝的:
$ nrm use cnpm
然后用 NPM 随便安装个什么,看看速度如何?是不是很快^_^
等等,Node.js 还有。有的开发依赖包是有 Node.js 版本依赖的,我们知道 Node.js 不同大版本的功能还是差别很大的,但我们又不会一遍遍的卸载安装吧?感觉好蠢!好吧,我们当然可以装一个nvm,nvm?好像和 nrm 很像!nvm 是 Node.js 的版本管理工具,可以在多个终端切换和运行不同的 Node.js 版本,可以到这里参考具体的安装教程。不过 nvm 在 windows 下不能使用,没关系,这里还有几个替代工具:nvm-window,gnvm 供你选择。
同样,我们执行下命令验证安装成果:
$ nvm --version 0.33.0项目初始化
有了上面的工具我们就可以开始创建一个项目了,我们执行以下命令来开始一个项目:
mkdir my-app cd my-app npm init
执行 npm init 后你会看到你需要输入项目的一些信息,完成后回车确认,然后npm会在根目录下创建一个叫 package.json 的文件,你之后通过 --save 或者 --save-dev 安装的依赖包都会出现在这个文件里。
先不管那么多,我们在根目录下创建一个 src 目录,然后在 src 下创建index.js、index.html……,好吧,你可以按照下面的结构新建文件:
. ├── 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
我们要想办法让这个页面跑起来,what??? 就这么简单?,把js引入 index.html 不就完事儿了嘛?当然没那么简单,我们可是要搞高大上的东西的呢!
哈~跑题了,我们继续。
首先我们要装一个叫 webpack 的东西,它是一个模块打包器,也就是我们俗称的构建工具,之前的那些 Grunt,Gulp 也都是构建工具,但是这年头流行 webpack 了!开个玩笑,webpack 的可扩展性和可插件化,以及把任何文件都视为模块的概念得到了前端社区的一致推崇,而且在打包效率和按需分割文件上都是其他几个构建工具无法相比较的,当然 webpack 的配置太灵活,官方文档写的太太太难看懂,也导致了很多初学者无从下手。
接下来我们就来配下这个神奇的工具吧。
自动构建我们先安装下 webpack:
npm install --save-dev webpack
然后在根目录下新建一个 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") } };
但要想在浏览器中访问还得有个本地服务器,好在 webpack 都帮我们想到了,我们可以装一个webpack-dev-server:
npm install --save-dev webpack-dev-server
我们在 package.json 中增加个 npm scripts:
"scripts": { "start": "webpack-dev-server --port 3003" },
ok!我们执行下 npm start,在浏览器中访问:http://localhost:3003。哎?好像哪里不对!是的,你得告诉 webpack,你的 bundle(打包后的 js)要插入到哪个 html 模板,前面说过,webpack 是插件化的,它把很多功能开放给了第三方来实现,他只是来负责拼装的,好,现在我们需要安装一个 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") }) ] }
再次执行 npm start,页面可以正常访问了。
但是,这样似乎有点 low,我们新增一个文件 utils.js,搞点es6语法:
. ├── 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);
刷新页面后好像也没什么异常(你肯定用了 chrome 吧!),仔细看控制台的 source 的 app.js(你的 bundle)的代码片段:
"use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = wordsToSentence; function wordsToSentence(...words) { return words.join(" "); }
值得注意的是,使用 ES6 时需要考虑那些没有支持 ES6 的旧浏览器,虽然在 chrome 或者其他高级浏览器中没有出现问题,但不能保证在其他浏览器中能正常运行。为了万无一失,我们需要将 ES6 转换为 ES5,也就是js代码转换器,这类工具当今世界就属 Babel 最牛逼了:
npm install --save-dev babel-loader babel-core
稍等,装了 Babel 还没法用,还得搞个 presets:
npm install --save-dev babel-preset-env
在根目录下新建个 .babelrc,输入配置:
{ "presets": ["env"] }
修改 webpack.config.js,增加 babel 的支持:
... module.exports = { ... module: { rules: [ { test: /.js$/, loader: "babel-loader", include: path.resolve(__dirname, "src") } ] }, ... };
执行 npm start,找到控制台 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(" "); }
已经成功转换成 ES5 代码。但是,目前 ES6 Modules 是由 Babel 来转的,你可以对比前后 2 次的代码片段的模块输出部分。现在,webpack 2 已经内 4 置了 ES6 Modules 的转换,据说效率和性能比 Babel 高!^_^没验证过哦,我们先试试,把 Babel 的模块转换关了先:
.babelrc
{ "presets": [ ["env", { "modules": false }] ] }
执行 npm start 再次查看输出后的 app.js 的代码片段:
-Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.wordsToSentence = wordsToSentence; +/* harmony export (immutable) */ __webpack_exports__["a"] = wordsToSentence; function wordsToSentence() { ... }
模块输出方式又回到了使用 Babel 前的代码。
js 的环境似乎已经准备就绪,但 css 还没上场,我们来修改下 index.css:
#app { color: #57af09; }
同时将 css 导入 bundle 入口,并修改下 index.js:
import "./index.css"; import { wordsToSentence } from "./utils/utils"; let el = document.createElement("div"), ... el.id = "app"; ...
有了样式还不行,webpack 还需要相应的 loader 来处理 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") } ] }, ... };
执行 npm start,现在可以看到页面已经有了样式。但是,我们说过,我们希望使用先进的武器: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";
由于文件(模块)类型变了,我们还需要一个 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") } ] }, ... };
执行 npm start,webpack 编译没有报错,页面显示一切正常!
代码自动更新(热更新)如果你尝试修改 index.scss 的样式,你有没注意到一个问题:页面会自动刷新。但有时候我们在开发一个模块,比如 dialog,刷新会导致你需要反复的在页面上操作才能看到这个 dialog 的样式更新。那我们有没有办法不刷新页面又能看到代码的更新呢?
其实很简单,因为 webpack-dev-server 已经内置了这样的功能,我们只要配置下 package.json的 npm scripts:
"scripts": { "start": "webpack-dev-server --hot --inline --port 3003" },
注意到上面的代码,我们增加了 --hot --inline,让开发环境有了热更新的能力。我们重新执行 npm start,然后将你的浏览器和编辑器并排放置,然后反复修改 index.scss,你会看到页面不会刷新,但样式在自动的推送更新,这就是传说中的热更新。
结束语到这里,简单(简陋)的、现代化的前端开发环境已经有了基本的雏形,但是,本篇文章不是webpack 的使用指南,也不是 ES6 的语法教程,尽管如此,还是希望你通过本篇文章感受到前端开发在工程化领域的发展带来的惊喜。
iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当开售。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/85135.html
摘要:前端日报精选如何优雅的编写代码深入理解内部机制专题之函数组合年月个有趣的和库最经典的前端面试题之一,你能答出什么幺蛾子中文翻译深入理解响应式原理掘金译与和交互掘金箭头函数使用禁忌技术栈耕耘助力美团点评前端进阶之路前端模块 2017-09-01 前端日报 精选 如何优雅的编写 JavaScript 代码深入理解 Node.js Stream 内部机制JavaScript专题之函数组合20...
摘要:马尔代夫之行重头戏这一年的工作情况这一年,个人感觉还是做了不少事情,主要集中在我们公司的前端领域,同时也给整个技术团队不少的建议,引入了不少新的东西和方式,总结起来比较重要的在下面五个方面。 如果想看技术相关的,下拉到后面的重头戏就是了。 一个活动页面 在15年末的时候,加入到罗辑思维,刚过来就接手了一个微信朋友圈要传播的活动页面,效果页面大概和当时锤子手机的活动页面漂亮的不像实力派类...
摘要:老姚浅谈怎么学鉴于时不时,有同学私信问我老姚,下同怎么学前端的问题。撸码听歌,全局控制。 浅析用 js 解析 xml 的方法 由于项目上需要解析 xml,于是各种百度,然后自己总结了下各个主流浏览器解析 xml 的方法,只能是很浅显的知道他的用法,但是还没有深层次的研究。 装 X - 建立自己的斗图网站库 之前加过一个斗图群,看到很多经典的表情,然后就收藏到了 QQ, 迫于本屌丝开不起...
阅读 1671·2023-04-26 00:30
阅读 3148·2021-11-25 09:43
阅读 2870·2021-11-22 14:56
阅读 3184·2021-11-04 16:15
阅读 1138·2021-09-07 09:58
阅读 2018·2019-08-29 13:14
阅读 3103·2019-08-29 12:55
阅读 982·2019-08-29 10:57