温馨的前端开发环境是怎样一种体验?

做者:Nicolas (沪江Web前端)
本文为原创文章,转载请注明做者及出处
本文的 webpack 代码示例根据 webpack 2.7.0 编写,并在 Mac 上正常运行。javascript

去年一篇《在 2016 年学 JavaScript 是一种什么样的体验?》吓坏了不少想要入行新同窗和入行好久的老司机,感受一会儿前端世界已经看不懂了,作个页面要那么麻烦?固然若是你只是想要一个简单的静态页面,这么玩儿就是杀鸡用牛刀了。但若是你准备开发一个 Web App,以后会不断的迭代,有一个温馨的开发环境是及其重要的,那么底怎么样的环境才会是温馨愉悦的呢?css

好比这样的一个环境:资源依赖能够安装并模块化引用、可使用很酷的 ES6 语法、可使用 SASS 预处理器写 CSS、代码可实时更新而不用一遍遍的手动刷新页面,这样的开发环境你会不会以为很爽!好,咱们这就来配置一个这样的环境!html

基础环境

首先,你须要一个 Node.js,而后 NPM 也会随着 Node.js 一块儿装上。前端

什么是 NPM ?简单的说 NPM 是用来下载安装 Node.js 的第三方工具包的一个管理器。固然,如今也能够安装浏览器中使用的包。提到包管理器,就不得不说下 Bower,Bower 以前一直是前端库管理工具,一开始 NPM 只能发布和安装 Node.js 的包,因此 Bower 盛行一时,随着 CommonJS 的普及,以及 UMD 规范的出现,让 NPM 安装前端浏览器 js 包成为了可能,随着 NPM 生态的成熟,Bower 也就慢慢被人淡忘了~java

Node.js 安装完成后,能够执行如下命令验证安装是否成功:node

$ 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。不细说了,咱们先装一个试试:webpack

$ npm install -g nrm

而后根据官方教程咱们先切一个国内的 registry,好比大淘宝的:git

$ nrm use cnpm

而后用 NPM 随便安装个什么,看看速度如何?是否是很快^_^es6

等等,Node.js 还有。有的开发依赖包是有 Node.js 版本依赖的,咱们知道 Node.js 不一样大版本的功能仍是差异很大的,但咱们又不会一遍遍的卸载安装吧?感受好蠢!好吧,咱们固然能够装一个nvm,nvm?好像和 nrm 很像!nvm 是 Node.js 的版本管理工具,能够在多个终端切换和运行不一样的 Node.js 版本,能够到这里参考具体的安装教程。不过 nvm 在 windows 下不能使用,不要紧,这里还有几个替代工具:nvm-windowgnvm 供你选择。github

一样,咱们执行下命令验证安装成果:

$ nvm --version
0.33.0

项目初始化

有了上面的工具咱们就能够开始建立一个项目了,咱们执行如下命令来开始一个项目:

mkdir my-app
cd my-app
npm init

执行 npm init 后你会看到你须要输入项目的一些信息,完成后回车确认,而后npm会在根目录下建立一个叫 package.json 的文件,你以后经过 --save 或者 --save-dev 安装的依赖包都会出如今这个文件里。

先无论那么多,咱们在根目录下建立一个 src 目录,而后在 src 下建立index.jsindex.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:

<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <title>My App</title>
</head>
<body>
</body>
</html>

咱们要想办法让这个页面跑起来,what??? 就这么简单?,把js引入 index.html 不就完事儿了嘛?固然没那么简单,咱们但是要搞高大上的东西的呢!

哈~跑题了,咱们继续。

首先咱们要装一个叫 webpack 的东西,它是一个模块打包器,也就是咱们俗称的构建工具,以前的那些 GruntGulp 也都是构建工具,可是这年头流行 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前端高效开发实战》已在亚马逊、京东、当当开售。

相关文章
相关标签/搜索