webpack 看我就够了(三)

如果没有看过webpack相关的东西,先看看webpack 你看我就够了(一)webpack 你看我就够了 (二)

webpack development server

webpack development server 是一个webpack可选的本地开发的server。它通过nodejs的express 来起一个server提供静态文件服务,同时它根据配置信息(xxx.config.js)来打包资源,存在内存中,同时当你的代码发生改变的时候,它还可以刷新你的浏览器。它是一个单独的npm module,通过npm install webpack-dev-server --save-dev来给项目安装依赖。

webpack dev server可以通过webpack.config.js的devServer选项来配置,具体配置包括:

  • contentBase: 默认webpack dev server是从项目的根目录提供服务,如果要从不同的目录提供服务,可以通过contentBase来配置,比如rails中可以把contentBase配置成'./public'。
  • port: 默认webpack是用 8080端口起的,通过port可以配成其他的端口。
  • inline: 设置为true,代码有变化,浏览器端刷新。
  • colors: 这个是当server跑的时候,terminal输出带颜色。
  • historyApiFallback: 这个是干嘛用的嘞?对于单页面程序,浏览器的brower histroy可以设置成html5 history api或者hash,而设置为html5 api的,如果刷新浏览器会出现404 not found,原因是它通过这个路径(比如: /activities/2/ques/2)来访问后台,所以会出现404,而把historyApiFallback设置为true那么所有的路径都执行index.html。

利用html5的history,生产环境的nginx可以这么配置,可以参考下

location / { 
  expires -1; add_header Pragma "no-cache"; 
  add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
 root /var/web;
 try_files $uri $uri/ /index.html =404; 
}

现在,我们可以把我们的小项目的 webpack.config.js重新配置一下,如下:

module.exports = {
  devtool: 'eval-source-map',
  entry: __dirname + "/app/main.js",
  output:   {
    path: __dirname + '/public',
    filename: 'bundle.js'
  },
  devServer: {
    contentBase: './public',
    color: true,
    historyApiFallback: true,
    inline: true
  }
}

现在不用跑webpack的命令,而直接跑webpack-dev-server这个命令就好了。如果只是安装了本地的依赖关系,那么就是执行./node_modules/.bin/webpack-dev-server好了。
效果如图:

Paste_Image.png

现在你可以把它写在我们的package.json中了。

具体如下:

{
"name": "webpack-sample-project",
 "version": "1.0.0",
"description": "Sample webpack project", 
"scripts": {
  "start": "node_modules/.bin/webpack-dev-server --progress" 
},
"author": "Cássio Zen", 
"license": "ISC", 
"devDependencies": {
  "webpack": "^1.12.9",
  "webpack-dev-server": "^1.14.0" 
}
}

progress命令行选项是用于显示build的进度

loaders

这个东东是webpack最显著的特点!!!!!!

webpack通过loader来加载各种各样的资源,不同的资源应用的不同的loader ,举个例子:打包es6会用到babel-loader,打包css用到style-loader和css-loader等等。
loaders是通过单独的npm来安装的,然后在webpack.config.js中通过module来配置。loader的配置包括:

  • test: 一个正则表达式,用于检测不同的文件的后缀名,然后配置配置不同的loader。
  • loader: loader的名字,比如'babel-loader'
  • include/exclude: 一个选项来配置哪些目录和文件需要排除掉或者加上
  • query: 这个query settings可以用于传递不同的参数给loader

举个例子,让我们把打招呼的信息放到一个单独的json文件中。
首先,我们先安装一个'json-loader',通过npm install json-loader --save-dev
下一步,我们来配置webpack.config.js,如下:

module.exports = {
  devTool: 'eval-source-map',
  entry: _dirname + '/app/main.js',
  output: {...},
  module: {
    loaders: [
      {
        test: /\.json$/,
        loader: "json"
      }
    ]
  },
  devServer:  {
    contentBase: './public',
    color: true,
    historyApiFallback: true,
    inline: true
  }
}

最后,我们创建一个config.json文件来写一些打招呼需要的信息,如下:

 {
  "greetText": "Hi there and greeting from JSON!"
 }

更新后的Greeter.js,如下:

var config = require('./config.json');
module.exports = function(){
  var greet = document.createElement('div');
  greet.textContent = config.greetText;
  return greet;
}

babel

babel是一个编译javascript的工具,它可以实现:

  1. 让你用下一代javascript(es6/es7/es2015/es2016)来写代码。
  2. 可以使用javascript的扩展语法,比如react jsx。

babel是一个单独的工具,但是我们可以通过babel-loader在webpack中应用它。

babel的安装和配置

babel是一个模块化的并且分发到不同的npm modules。核心的功能 babel-core 是通过babel-loader按装来直接使用的。但是,对于一些其他的功能和扩展要另外的安装(最常用的是babel-preset-es2015和babel-preset-react分别用于支持es6和react jsx)。
我们来安装所需的包npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
像其他的laoder一样,可以通过配置文件来配置。下面是更新后的webpack.config.js

module.exports = {
  devtool: 'eval-source-map',
  entry: __dirname + "/app/main.js", output: {...},
  module: {
    loaders: [
        {
          test: /\.json$/, loader: "json"
        },
        {
          test: /\.js$/,
          exclude: /node_modules/, loader: 'babel',
          query: {
            presets: ['es2015','react'] }
        }
      ]},
  devServer: {
    contentBase: "./public", 
    colors: true, 
    historyApiFallback: true, 
    inline: true
  }
}

现在我们的项目可以利用es6的属性和react的jsx,现在让我们来给我们的项目引入react和react-dom。

现在重构我们的Greeter.js,如下:

import React, {Component} from 'react';
import config from './config.json';
class Greeter extends Component {
  render() {
    return (
      <div>
        {config.greetText}
      </div>
    );
  }
}

export default Greeter;

现在来重构我们的main.js,如下:

import React from 'react';
import {render} from 'react-dom';
import Greeter from './Greeter';

render(<Greeter/>, document.getElementById('root'));
babel的配置文件

babel可以通过webpack的配置文件直接配置,但是它有很多的配置信息,都放到同一个webpack的配置文件中会使得配置文件不好维护。因为这个原因很多的开发者选择了单独的babel配置文件'.babelrc',来配置bebel的选项等等。
目前我们对babel的配置只是presets,所以我们先把这个配置放到'.babelrc'中吧,后面会一些别的配置信息的。

现在我们的webpack的配置信息如下:

module.exports = {
  devtool: 'eval-source-map',
  entry: __dirname + '/app/main.js',
  output: {...},
  module: {
    loaders: [
      {
        test: /\.json$/,
        loader: 'json'
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel'
      }
  ]
  },
  devServer: {...}
}

去掉了对babel loader的presets配置,那么.babelrc文件如下:

{
  "presets": ["react", "es2015"]
}

其他资源(除了javascript)

webpack最大的一个特点就是能把各种各样的文件当做module来对待调用。这些资源文件包括 js,css, font, image 等等。webpack能够通过@import和url值等相应的处理css文件的依赖关系,编译打包。

样式表

webpack提供了css-loader和style-loader来处理样式表。不同的loader处理不同的任务,其中css-loader处理@import和url值来解决他们的依赖关系,然后style-loader把这些计算后的样式表加到页面上。总结来说呢,就是这两个loader共同实现了把样式表嵌入到webpack的js bundle中。

现在把这两个loader添加到我们的小项目中。

首先通过npm来安装 npm install --save-dev style-loader css-loader

然后更新我们的webpack配置文件

module.exports = {
  devtool: 'eval-source-map',
  entry: __dirname + '/app/main.js',
  output: {...},
  module: {
    loaders: [
      {test: /\.json$/, loader: "json"},
      {test: /\.js$/, exclude: /node_modules/, loader: 'babel'},
      {test: /\.css$/, loader: 'style!css'}
    ]
  },
devServer: {...}
}

注意 loader中的(!)这个符号用于连接不同的loader的,在这里就是.css文件要被style-loader和css-loader同时处理。

现在呢,我们来新建一个main.css来写一些基本的样式,用于我们的小程序。

main.css如下:

html {
  box-sizing: border-box;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
}
*, *:before, *:after { 
  box-sizing: inherit;
}
body {
  margin: 0;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
h1, h2, h3, h4, h5, h6, p, ul { 
  margin: 0;
  padding: 0;
}

最后记住我们的webpack是起始于一个或多个entry point文件的,然后分析依赖关系等等,再进行打包。这里我们的entry point文件是 main.js,所以我们要在main.js中引用main.css就像引用js一样引用,这个是不是很酷??,好了main.js加上下面那一句。

import './main.css';
css 模块

在过去几年中,javascript发生了很多的变化,添加了很多的语言功能,同时更多更好的前段工具化使得开发更加高效同时建立一些最好的实践(best pratice)例如modules。

模块使得开发者可以把代码分成很多小的单独的单元,然后声明之间的依赖关系。通过好的优化工具,依赖管理,依赖顺序自动会被解决。

但是随着javascript的发展,css还是单片的,全局的,使得开发越来越难以维护和复杂。

最近一个项目叫做'css modules'目的就是把模块化等等的特点带给css。通过css modules,所有的css的classname和animation name都是本地scoped。webpack从一开始就加入了这个项目在css loader中,只是我们需要显示的开启它。有了这个功能,你可以export class来给指定的component。
这样说可能比较抽象,那么我们来把这个功能添加到我们的项目当中。

module.exports = {
  devtool: 'eval-source-map',
  entry: __dirname + "/app/main.js", output: {...},
  module: {
    loaders: [
        { test: /\.json$/, loader: "json" },
        { test: /\.js$/, exclude: /node_modules/, loader: 'babel' }, {
        test: /\.css$/,
        loader: 'style!css?modules' }
        ] 
  },
  devServer: {...}
}

现在我们来创建一个Greeting.css文件,然后在Greeter.js中引用这个文件,应用这个css文件中定义的class,具体代码如下:

Greeting.css代码:

.root {
  background-color: #eee,
  padding: 10px;
  border: 3px solid #ccc;
}

那么我们的Greeting.js代码变更如下:

import React, {Component} from 'react'; 
import config from './config.json'; 
import styles from './Greeter.css';
class Greeter extends Component{ 
  render() {
    return (
      <div className={styles.root}>
      {config.greetText} </div>
    ); 
  }
}
export default Greeter

注意到css怎么被一个变量引用,然后应用的一个jsx的element上的。

这个是不是很酷,一些通用的class可以这样被本地性的引用,不会受到命名冲撞的影响。

css modules是一个比较大的主题,而且还有很多的功能实现,想了解更多可以查看这个

css的预处理器

css的预处理比如sass less stylus 都扩展扩展了css的语法。他们让我们可以利用一些css中没有的功能来写css,比如变量,函数,嵌套,mixins等等。其实从概念上 es6/coffeescript 转译成 js和sass等转译成css是相似的。

正如你想象的那样,在webpack中可以利用相应的loader来处理这些预编译。

一个新的趋势更加宽松的css工作流程是通过应用PostCSS来实现的。不是通过一个完整的,固定的css语言,PostCSS是一个css转译工具。通过连接不同的插件,来应用不用的转译到你的css文件。你可以了解更多通过这个
这里我们通过PostCSS和autoprefixer插件来举例子,其中autoprefixer是给我们的css自动添加浏览器供应商前缀。
首先安装这些包, npm install --save-dev postcss-loader autoprefixer
现在我们来重新配置webpack,如下:

module.exports = {
  devtool: 'eval-source-map',
  entry: __dirname + "/app/main.js", 
  output: {...},
  module: {
    loaders: [
      { test: /\.json$/, loader: "json" },
      { test: /\.js$/, exclude: /node_modules/, loader: 'babel' }, 
      {
        test: /\.css$/,
        loader: 'style!css?modules!postcss'
      } ]
  },
  postcss: [ require('autoprefixer')],
  devServer: {...} 
}

下一个系列我们会了解一些webpack插件的知识,和生产环境相关的配置。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容