作者:Nicolas(沪江网前端)本文为原创文章,转载请注明作者及出处。本文中的webpack代码示例是根据webpack2.7.0编写的,在Mac上运行正常。去年的文章《在 2016 年学 JavaScript 是一种什么样的体验?》吓坏了很多想入行的新同学和入行已久的老司机。感觉前端的世界一下子看不懂了。做一个页面有多麻烦?当然,如果你只是想要一个简单的静态页面,这么玩简直就是杀鸡用牛刀。但是如果你要开发一个WebApp,后面还会不断迭代,那么有一个舒适的开发环境是极其重要的,那么什么样的环境才会舒适愉快呢?比如这样一个环境:可以安装和模块化资源依赖,可以使用炫酷的ES6语法,可以使用SASS预处理器编写CSS,代码可以实时更新,无需手动一遍又一遍的刷新页面。不会觉得很爽!好了,我们来配置这样一个环境吧!基础环境首先需要一个Node.js,然后NPM会随着Node.js一起安装。什么是NPM?简单来说,NPM就是一个下载安装Node.js第三方工具包的管理器。当然,现在也可以安装在浏览器中使用的包。说到包管理器,就不得不说到Bower。Bower一直是前端库管理工具。一开始,NPM只能发布和安装Node.js包,所以Bower流行了一段时间。随着CommonJS的流行和UMD规范的出现,NPM的出现使得在NPM上安装前端浏览器js包成为可能。随着NPM生态的成熟,Bower也逐渐被遗忘~Node.js安装完成后,可以执行以下命令来验证是否安装成功:$node-vv6.11.0$npm-v3.10.10别担心,Node.js部分还没有完成。国内通过npm官方源安装依赖貌似很慢,等了好久。如何解决?我们可以安装一个nrm!nrm是一个npm注册表管理工具。您可以在npm注册中心之间自由切换,然后在命令行上使用npm。国内有很多npm的镜像,比如淘宝的cnpm。但是,很多公司都建立了自己的私人图书馆。什么是私人图书馆?私有库是一个npm包,只能在公司内网访问,不能发布到npm共享平台。比如我们大公司私有库的registry名称是hnpm。不细说了,我们先安装一个试试:$npminstall-gnrm然后按照官方教程,先切一个国内的registry,比如淘宝的:$nrmusecnpm然后用npm随便装个啥到看速度如何?很快吗^_^等等,Node.js等等。一些开发依赖包依赖于Node.js版本。我们知道Node.js不同大版本的功能还是有很大区别的,但是我们不会卸载再安装一遍又一遍吧?觉得好傻!好吧,我们当然可以安装一个nvm,nvm?好像和nrm很像啊!nvm是Node.js的版本管理工具。它可以在多个终端切换和运行不同的Node.js版本。具体安装教程可以参考这里。不过nvm不能在windows下使用,没关系,这里有几个替代工具:nvm-window、gnvm供你选择。同样,我们执行以下命令来验证安装结果:$nvm--version0.33.0项目初始化有了以上工具,我们就可以开始创建项目了,我们执行以下命令来启动一个项目:mkdirmy-appcdmy-appnpminit执行npminit后,会看到需要输入项目的一些信息,完成后回车确认,然后npm会在根目录下创建一个名为package.json的文件,你会通过--save或--save-dev安装的依赖项将出现在这个文件中。不管怎样,我们在根目录下创建一个src目录,然后在src下创建index.js、index.html……嗯,可以按照下面的结构新建文件:.├──package.json└──src├──index.css├──index.html└──index.js在以下文件中输入代码:index.js:varel=document.createElement('div'),text=document.createTextNode('我的应用程序');el.appendChild(text);document.body.appendChild(el);index.html:
MyApp我们必须想办法让这个页面运行起来,什么???就这么简单?,不都是在index.html中引入js就搞定了吗?当然没那么简单,我们要做高端的东西!哈~跑题了,我们继续。首先我们需要安装一个叫webpack的东西,它是一个模块打包器,也就是我们俗称的构建工具。以前的Grunt和Gulp也是构建工具,但是webpack这几年流行!开个玩笑,webpack的可扩展性和可插拔性,以及将任何文件都当做一个模块的理念已经得到了前端社区的一致推崇,而其他几个构建工具在打包效率和按需拆分文件方面做不到。相比之下,当然webpack的配置过于灵活,官方文档过于难懂,也让很多初学者无从下手。接下来,让我们匹配这个神奇的工具。自动构建,我们先安装webpack:npminstall--save-devwebpack然后在根目录新建webpack.config.js文件,输入如下代码:letpath=require('path');module.exports={entry:{app:path.resolve(__dirname,'src','index.js')},输出:{filename:'[name].js',path:path.resolve(__dirname,'dist')}};但是如果你想在浏览器中访问它,你需要一个本地服务器。幸运的是,webpack已经帮我们想到了。我们可以安装一个webpack-dev-server:npminstall--save-devwebpack-dev-server。我们在包里。在json中加入npmscripts:"scripts":{"start":"webpack-dev-server--port3003"},ok!我们执行npmstart,在浏览器中访问:http://localhost:3003。为什么?好像不对劲!是的,你必须告诉webpack你的包(打包的js)应该插入到哪个html模板中。前面说了,webpack是插件化的,它把很多功能开放给第三方实现。他只负责组装好了,好了,现在我们需要安装一个html-webpack-plugin插件:npminstall--save-devhtml-webpack-plugin修改webpack-config.js:letHtmlWebpackPlugin=require('html-webpack-plugin'),path=require('path');module.exports={entry:{...},...plugins:[newHtmlWebpackPlugin({template:path.resolve(__dirname,'src','index.html')})]}再次执行npmstart,页面可以正常访问了。然而,这似乎有点低,我们添加一个新文件utils.js,并使用一些es6语法:.├──package.json└──src├──index.css├──index.html├──index.js+└──utils+└──utils.jsutils.js:exportfunctionwordsToSentence(...words){returnwords.join('');}修改index.js+import{wordsToSentence}from'./utils/utils';让el=document.createElement('div'),-text=document.createTextNode('MyApp');+text=document.createTextNode(+wordsToSentence('Welcome','to','my','app!')+);el.appendChild(text);document.body.appendChild(el);刷新页面后好像没有异常(你肯定用过chrome!),仔细看源码app.js的控制台(你捆绑)代码片段:“usestrict”;/*harmonyexport(immutable)*/__webpack_exports__["a"]=wordsToSentence;functionwordsToSentence(...words){returnwords.join('');值得注意的是,在使用ES6的时候,需要考虑那些不支持ES6的老浏览器。虽然在chrome或其他高级浏览器中没有问题,但不能保证在其他浏览器中也能正常使用。为了万无一失,我们需要将ES6转ES5,也就是js代码转换器。这种工具是当今世界上最好的:Babel:npminstall--save-devbabel-loaderbabel-core等一下,安装Babel还不行,得创建预设:npminstall--save-devbabel-preset-env在根目录新建.babelrc,进入配置:{"presets":["env"]}修改webpack.config.js,添加babel支持:...module.exports={...module:{rules:[{test:/\.js$/,loader:'babel-loader',include:path.resolve(__dirname,'src')}]},...};执行npmstart,在consolesource下找到app.js代码片段:"usestrict";Object.defineProperty(exports,"__esModule",{value:true});exports.wordsToSentence=wordsToSentence;functionwordsToSentence(){for(var_len=arguments.length,words=Array(_len),_key=0;_key<_len;_key++){words[_key]=arguments[_key];}returnwords.join('');}已经成功转换成ES5代码。不过目前ES6Modules是通过Babel转换的,大家可以对比前后两个代码片段的模块输出部分。现在,webpack2内置了ES6Modules的转换,据说比Babel更高效、更高效!^_^没验证过,先试试,先关掉Babel的模块转换:.babelrc{"presets":[["env",{"modules":false}]]}执行npmstart再检查app.js输出后的代码片段:-Object.defineProperty(exports,"__esModule",{-value:true-});-exports.wordsToSentence=wordsToSentence;+/*harmonyexport(immutable)*/__webpack_exports__["a"]=wordsToSentence;functionwordsToSentence(){...}模块输出方法返回使用Babel之前的代码。js环境好像准备好了,但是css还没玩,我们修改index.css:#app{color:#57af09;}把css导入bundle入口,修改index.js:import'./index.css';import{wordsToSentence}from'./utils/utils';letel=document.createElement('div'),...el.id='app';...样式是还不够,webpack还需要相应的loader来处理css模块:npmi--save-devstyle-loadercss-loader修改webpack.config.js:...module.exports={...module:{规则:[。..{test:/\.css$/,loader:['style-loader','css-loader'],include:path.resolve(__dirname,'src')}]},...};执行npmstart,现在可以看到页面有了样式。但是,正如我们所说,我们想使用一种先进的武器: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';由于文件(模块)类型发生了变化,我们还需要一个SASSwebpackloader:npminstall--save-devsass-loadernode-sass再次修改webpack.config.js:...module.exports={...模块:{规则:[...{-测试:/\.css$/,+测试:/\.scss$/,-加载器:['style-loader','css-loader'],+加载器:['style-loader','css-loader','sass-loader'],include:path.resolve(__dirname,'src')}]},...};执行npmstart,webpack编译没有报错,页面显示一切正常!代码自动更新(热更新)如果你尝试修改index.scss的样式,你有没有注意到一个问题:页面会自动刷新。但是有时候我们在开发一个模块的时候,比如dialog,刷新会导致你需要在页面上反复操作才能看到这个dialog的样式更新。那么有什么办法可以在不刷新页面的情况下看到代码更新呢?其实很简单,因为webpack-dev-server内置了这样一个功能,我们只需要配置package.json的npmscripts:"scripts":{"start":"webpack-dev-server--hot--inline--port3003"},注意到上面的代码,我们添加了--hot--inline,让开发环境具备热更新的能力。我们重新执行npmstart,然后将你的浏览器和编辑器并排放置,然后反复修改index.scss,你会看到页面不会刷新,但是样式会自动更新,也就是传说中的热更新。结论至此,一个简单(粗糙)且现代的前端开发环境有了一个基本的原型。但是,本文不是webpack的使用指南,也不是ES6的语法教程。尽管如此,还是希望你通过这篇文章感受前端开发在工程领域的发展所带来的惊喜。iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当网发售。