webpack 学习

我的

webpack.config.js

module.exports = {
	entry: [
		'./src/js/app.js',
		'./src/js/my.js'
	],
	output: {
		path: __dirname + '/output/',
		publicPath: "/output/",
		filename: 'main.js'
	},
	module: {
     loaders: [
         {test: /\.(jpg|png)$/, loader: "url?limit=8192"},
         { test: /\.css$/, loader: "style!css" }
     ]
 }
};

package.json

{
	"name": "webpack",
	"version": "0.0.1",
	"description": "webpack",
	"main": "index.js",
	"scripts": {
		"test": "npm start"
	},
	"author": "libin",
	"license": "ISC"
}

 index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="output/main.js"></script>
	</head>
	<body>
		<p></p>
	</body>
</html>

app.js

document.write(require('./my.js'));

my.js      

require('../css/app.css');    //会将此css文件打到页面里面
module.exports = "webpack现在的内容是来自于my.js文件!";

a.png

  

app.css

body{
	background: green;
	text-align: center;
	font-size: 25px;
	border: 100px solid red;
}
p{
	width: 100px;
	height: 100px;
	background:url(../img/a.png);
}

最后生成的output 文件main.js

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "/output/";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	__webpack_require__(1);
	module.exports = __webpack_require__(2);


/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

	document.write(__webpack_require__(2));

/***/ },
/* 2 */
/***/ function(module, exports) {

	module.exports = "webpack现在的内容是来自于my.js文件!";

/***/ }
/******/ ]);

 

执行:

webpack-dev-server --progress --colors

浏览器打开:

 

 

 

 

 

 

 

 

 

 

 

如今,越来越多的JavaScript代码被使用在页面上,我们添加很多的内容在浏览器里。如何去很好的组织这些代码,成为了一个必须要解决的难题。

对于模块的组织,通常有如下几种方法:

  1. 通过书写在不同文件中,使用script标签进行加载
  2. CommonJS进行加载(NodeJS就使用这种方式)
  3. AMD进行加载(require.js使用这种方式)
  4. ES6模块

思考:为什么只有JS需要被模块化管理,前台的很多预编译内容,不需要管理吗?

基于以上的思考,WebPack项目有如下几个目标:

  • 将依赖树拆分,保证按需加载
  • 保证初始加载的速度
  • 所有静态资源可以被模块化
  • 可以整合第三方的库和模块
  • 可以构造大系统

从下图可以比较清晰的看出WebPack的功能


这是一个示意图

WebPack的特点

  1. 丰富的插件,方便进行开发工作
  2. 大量的加载器,包括加载各种静态资源
  3. 代码分割,提供按需加载的能力
  4. 发布工具

WebPack的优势

  • webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
  • 能被模块化的不仅仅是 JS 了。
  • 开发便捷,能替代部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等。
  • 扩展性强,插件机制完善,特别是支持 React 热插拔(见 react-hot-loader )的功能让人眼前一亮。

WebPack的安装

  1. 安装命令
    $ npm install webpack -g
  2. 使用webpack
    $ npm init  # 会自动生成一个package.json文件
    $ npm install webpack --save-dev #将webpack增加到package.json文件中
  3. 可以使用不同的版本
    $ npm install webpack@1.2.x --save-dev
  4. 如果想要安装开发工具
    $ npm install webpack-dev-server --save-dev

WebPack的配置

每个项目下都必须配置有一个 webpack.config.js ,它的作用如同常规的 gulpfile.js/Gruntfile.js ,就是一个配置项,告诉 webpack 它需要做什么。

下面是一个例子

var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
module.exports = {
    //插件项
    plugins: [commonsPlugin],
    //页面入口文件配置
    entry: {
        index : './src/js/page/index.js'
    },
    //入口文件输出配置
    output: {
        path: 'dist/js/page',
        filename: '[name].js'
    },
    module: {
        //加载器配置
        loaders: [
            { test: /\.css$/, loader: 'style-loader!css-loader' },
            { test: /\.js$/, loader: 'jsx-loader?harmony' },
            { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
            { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
        ]
    },
    //其它解决方案配置
    resolve: {
        root: 'E:/github/flux-example/src', //绝对路径
        extensions: ['', '.js', '.json', '.scss'],
        alias: {
            AppStore : 'js/stores/AppStores.js',
            ActionType : 'js/actions/ActionType.js',
            AppAction : 'js/actions/AppAction.js'
        }
    }
};
  1. plugins 是插件项,这里我们使用了一个 CommonsChunkPlugin的插件,它用于提取多个入口文件的公共脚本部分,然后生成一个 common.js 来方便多页面之间进行复用。
  2. entry 是页面入口文件配置,output 是对应输出项配置 (即入口文件最终要生成什么名字的文件、存放到哪里)
  3. module.loaders 是最关键的一块配置。它告知 webpack 每一种文件都需要使用什么加载器来处理。 所有加载器需要使用npm来加载
  4. 最后是 resolve 配置,配置查找模块的路径和扩展名和别名(方便书写)

WebPack开始使用

这里有最基本的使用方法,给大家一个感性的认识

  1. 正确安装了WebPack,方法可以参考上面
  2. 书写entry.js文件
    document.write("看看如何让它工作!");
  3. 书写index.html文件
    <html>
    <head>
    <meta charset="utf-8">
    </head>
    <body>
    <script type="text/javascript" src="bundle.js" charset="utf-8"></script>
    </body>
    </html>
  4. 执行命令,生成bundle.js文件
    $ webpack ./entry.js bundle.js
  5. 在浏览器中打开index.html文件,可以正常显示出预期
  6. 增加一个content.js文件
    module.exports = "现在的内容是来自于content.js文件!";
  7. 修改entry.js文件
    document.write(require("./content.js"));
  8. 执行第四步的命令

进行加载器试验

  1. 增加style.css文件
    body {
    background: yellow;
    }
  2. 修改entry.js文件
    require("!style!css!./style.css");
    document.write(require("./content.js"));
  3. 执行命令,安装加载器
    $ npm install css-loader style-loader   # 安装的时候不使用 -g
  4. 执行webpack命令,运行看效果
  5. 可以在命令行中使用loader
    $ webpack ./entry.js bundle.js --module-bind "css=style!css"

使用配置文件
默认的配置文件为webpack.config.js

  1. 增加webpack.config.js文件
    module.exports = {
     entry: "./entry.js",
     output: {
         path: __dirname,
         filename: "bundle.js"
     },
     module: {
         loaders: [
             { test: /\.css$/, loader: "style!css" }
         ]
     }
    };
  2. 执行程序
    $ webpack

发布服务器

  1. 安装服务器
    $ npm install webpack-dev-server -g
    $ webpack-dev-server --progress --colors
  2. 服务器可以自动生成和刷新,修改代码保存后自动更新画面
    http://localhost:8080/webpack-dev-server/bundle



文/hutou(简书作者)
原文链接:http://www.jianshu.com/p/b95bbcfc590d
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
 
 
 
 
 
webpack 的优势

其优势主要可以归类为如下几个:

1. webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。

2. 能被模块化的不仅仅是 JS 了。

3. 开发便捷,能替代部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等。

4. 扩展性强,插件机制完善,特别是支持 React 热插拔(见 react-hot-loader )的功能让人眼前一亮。

我们谈谈第一点。以 AMD/CMD 模式来说,鉴于模块是异步加载的,所以我们常规需要使用 define 函数来帮我们搞回调:

define(['package/lib'], function(lib){

function foo(){
lib.log('hello world!');


return {
foo: foo
};
});

另外为了可以兼容 commonJS 的写法,我们也可以将 define 这么写:

define(function (require, exports, module){
var someModule = require("someModule");
var anotherModule = require("anotherModule"); 
someModule.doTehAwesome();
anotherModule.doMoarAwesome();
exports.asplode = function (){
someModule.doTehAwesome();
anotherModule.doMoarAwesome();
};
});

然而对 webpack 来说,我们可以直接在上面书写 commonJS 形式的语法,无须任何 define (毕竟最终模块都打包在一起,webpack 也会最终自动加上自己的加载器):

var someModule = require("someModule");
var anotherModule = require("anotherModule"); 
someModule.doTehAwesome();
anotherModule.doMoarAwesome();
exports.asplode = function (){
someModule.doTehAwesome();
anotherModule.doMoarAwesome();
};

这样撸码自然更简单,跟回调神马的说 byebye~

不过即使你保留了之前 define 的写法也是可以滴,毕竟 webpack 的兼容性相当出色,方便你旧项目的模块直接迁移过来。


一小时包教会 —— webpack 入门指南
安装和配置 一. 安装

我们常规直接使用 npm 的形式来安装:

$ npm install webpack -g

当然如果常规项目还是把依赖写入 package.json 包去更人性化:

$ npm init$ npm install webpack --save-dev

二. 配置

每个项目下都必须配置有一个 webpack.config.js ,它的作用如同常规的 gulpfile.js/Gruntfile.js ,就是一个配置项,告诉 webpack 它需要做什么。

我们看看下方的示例:

var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
module.exports = {
//插件项
plugins: [commonsPlugin],
//页面入口文件配置
entry: {
index : './src/js/page/index.js'
},
//入口文件输出配置
output: {
path: 'dist/js/page',
filename: '[name].js'
},
module: {
//加载器配置
loaders: [
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.js$/, loader: 'jsx-loader?harmony' },
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
]
},
//其它解决方案配置
resolve: {
root: 'E:/github/flux-example/src', //绝对路径
extensions: ['', '.js', '.json', '.scss'],
alias: {
AppStore : 'js/stores/AppStores.js',
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}
};

⑴ plugins 是插件项,这里我们使用了一个 CommonsChunkPlugin的插件,它用于提取多个入口文件的公共脚本部分,然后生成一个 common.js 来方便多页面之间进行复用。

⑵ entry 是页面入口文件配置,output 是对应输出项配置 (即入口文件最终要生成什么名字的文件、存放到哪里) ,其语法大致为:

{
entry: {
page1: "./page1",
//支持数组形式,将加载数组中的所有模块,但以最后一个模块作为输出
page2: ["./entry1", "./entry2"]
},
output: {
path: "dist/js/page",
filename: "[name].bundle.js"
}
}

该段代码最终会生成一个 page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夹下。

⑶ module.loaders 是最关键的一块配置。它告知 webpack 每一种文件都需要使用什么加载器来处理:

module: {
//加载器配置
loaders: [
//.css 文件使用 style-loader 和 css-loader 来处理
{ test: /\.css$/, loader: 'style-loader!css-loader' },
//.js 文件使用 jsx-loader 来编译处理
{ test: /\.js$/, loader: 'jsx-loader?harmony' },
//.scss 文件使用 style-loader、css-loader 和 sass-loader 来编译处理
{ test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
//图片文件使用 url-loader 来处理,小于8kb的直接转为base64
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
]
}

如上,"-loader"其实是可以省略不写的,多个loader之间用“!”连接起来。

注意所有的加载器都需要通过 npm 来加载,并建议查阅它们对应的 readme 来看看如何使用。

拿最后一个 url-loader 来说,它会将样式中引用到的图片转为模块来处理,使用该加载器需要先进行安装:

npm install url-loader -save-dev

配置信息的参数“?limit=8192”表示将所有小于8kb的图片都转为base64形式 (其实应该说超过8kb的才使用 url-loader 来映射到文件,否则转为data url形式) 。

你可以 点这里 查阅全部的 loader 列表。

⑷ 最后是 resolve 配置,这块很好理解,直接写注释了:

resolve: {
//查找module的话从这里开始查找
root: 'E:/github/flux-example/src', //绝对路径
//自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
extensions: ['', '.js', '.json', '.scss'],
//模块别名定义,方便后续直接引用别名,无须多写长长的地址
alias: {
AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}

关于 webpack.config.js 更详尽的配置可以参考 这里 。


一小时包教会 —— webpack 入门指南
运行 webpack

webpack 的执行也很简单,直接执行

$ webpack --display-error-details

即可,后面的参数“--display-error-details”是推荐加上的,方便出错时能查阅更详尽的信息(比如 webpack 寻找模块的过程),从而更好定位到问题。

其他主要的参数有:

$ webpack --config XXX.js //使用另一份配置文件(比如webpack.config2.js)来打包
$ webpack --watch //监听变动并自动打包
$ webpack -p //压缩混淆脚本,这个非常非常重要!
$ webpack -d //生成map映射文件,告知哪些模块被最终打包到哪里了

其中的 -p 是很重要的参数,曾经一个未压缩的 700kb 的文件,压缩后直接降到 180kb (主要是样式这块一句就独占一行脚本,导致未压缩脚本变得很大) 。


一小时包教会 —— webpack 入门指南
模块引入

上面唠嗑了那么多配置和执行方法,下面开始说说寻常页面和脚本怎么使用呗。

一. HTML

直接在页面引入 webpack 最终生成的页面脚本即可,不用再写什么 data-main 或seajs.use 了:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<script src="dist/js/page/common.js"></script>
<script src="dist/js/page/index.js"></script>
</body>
</html>

可以看到我们连样式都不用引入,毕竟脚本执行时会动态生成<style>并标签打到head里。

二. JS

各脚本模块可以直接使用 commonJS 来书写,并可以直接引入未经编译的模块,比如 JSX、sass、coffee等(只要你在 webpack.config.js 里配置好了对应的加载器)。

我们再看看编译前的页面入口文件(index.js):

require('../../css/reset.scss'); //加载初始化样式
require('../../css/allComponent.scss'); //加载组件样式
var React = require('react');
var AppWrap = require('../component/AppWrap'); //加载组件
var createRedux = require('redux').createRedux;
var Provider = require('redux/react').Provider;
var stores = require('AppStore');
var redux = createRedux(stores);
var App = React.createClass({
render: function() {
return (
<Provider redux={redux}>
{function() { return <AppWrap />; }}
</Provider>
);
}
});
React.render(
<App />, document.body
);

一切就是这么简单么么哒~ 后续各种有的没的,webpack 都会帮你进行处理。


一小时包教会 —— webpack 入门指南
其他

至此我们已经基本上手了 webpack 的使用,下面是补充一些有用的技巧。

一. shimming

在 AMD/CMD 中,我们需要对不符合规范的模块(比如一些直接返回全局变量的插件)进行 shim 处理,这时候我们需要使用 exports-loader 来帮忙:

{ test: require.resolve("./src/js/tool/swipe.js"), loader: "exports?swipe"}

之后在脚本中需要引用该模块的时候,这么简单地来使用就可以了:

require('./tool/swipe.js');
swipe(); 
一小时包教会 —— webpack 入门指南
二. 自定义公共模块提取

在文章开始我们使用了CommonsChunkPlugin 插件来提取多个页面之间的公共模块,并将该模块打包为 common.js 。

但有时候我们希望能更加个性化一些,我们可以这样配置:

var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
p1: "./page1",
p2: "./page2",
p3: "./page3",
ap1: "./admin/page1",
ap2: "./admin/page2"
},
output: {
filename: "[name].js"
},
plugins: [
new CommonsChunkPlugin("admin-commons.js", ["ap1", "ap2"]),
new CommonsChunkPlugin("commons.js", ["p1", "p2", "admin-commons.js"])
]
};
// <script>s required:
// page1.html: commons.js, p1.js
// page2.html: commons.js, p2.js
// page3.html: p3.js
// admin-page1.html: commons.js, admin-commons.js, ap1.js
// admin-page2.html: commons.js, admin-commons.js, ap2.js 
一小时包教会 —— webpack 入门指南
三. 独立打包样式文件

有时候可能希望项目的样式能不要被打包到脚本中,而是独立出来作为.css,然后在页面中以<link>标签引入。这时候我们需要 extract-text-webpack-plugin 来帮忙:

var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
plugins: [commonsPlugin, new ExtractTextPlugin("[name].css")],
entry: {
//...省略其它配置

最终 webpack 执行后会乖乖地把样式文件提取出来:


一小时包教会 —— webpack 入门指南

一小时包教会 —— webpack 入门指南
四. 与 grunt/gulp 配合

以 gulp 为示例,我们可以这样混搭:

gulp.task("webpack", function(callback) {
// run webpack
webpack({
// configuration
}, function(err, stats) {
if(err) throw new gutil.PluginError("webpack", err);
gutil.log("[webpack]", stats.toString({
// output options
}));
callback();
});
});

当然我们只需要把配置写到 webpack({ ... }) 中去即可,无须再写 webpack.config.js 了。

更多参照信息请参阅: grunt配置 / gulp配置 。

 

 

 


一小时包教会 —— webpack 入门指南
五. React 相关

⑴ 推荐使用 npm install react 的形式来安装并引用 React 模块,而不是直接使用编译后的 react.js,这样最终编译出来的 React 部分的脚本会减少 10-20 kb左右的大小。

⑵ react-hot-loader 是一款非常好用的 React 热插拔的加载插件,通过它可以实现修改-运行同步的效果,配合 webpack-dev-server 使用更佳!

基于 webpack 的入门指引就到这里,希望本文能对你有所帮助,你也可以参考下述的文章来入门:

webpack入门指谜

webpack-howto

共勉~

 

 

 

 

最近在看许多React的资料,发现了大部分的项目都是用webpack行模块化管理的工具。这次也是借着写了一个React-Todos的小应用,对webPack最基本实用的功能体验了一番,顺带做个小记录。

#为什么用webpack

CommonJs与AMD

在一开始,我们先讲一下它和以往我们所用的模块管理工具有什么不一样。在最开始的阶段,Js并没有这些模块机制,各种Js到处飞,得不到有效妥善的管理。后来前端圈开始制定规范,最耳熟能详的是CommonJs和AMD。

CommonJs是应用在NodeJs,是一种同步的模块机制。它的写法大致如下:

var firstModule = require("firstModule");

//your code...

module.export = anotherModule

AMD的应用场景则是浏览器,异步加载的模块机制。require.js的写法大致如下:

define(['firstModule'], function(module){
  
  //your code...
  return anotherModule
})

其实我们单比较写法,就知道CommonJs是更为优秀的。它是一种同步的写法,对Human友好,而且代码也不会繁琐臃肿。但更重要的原因是, 随着npm成为主流的JavaScript组件发布平台,越来越多的前端项目也依赖于npm上的项目,或者自身就会发布到npm平台。 所以我们对如何可以使用npm包中的模块是我们的一大需求。所以browserify工具就出现了,它支持我们直接使用 require() 的同步语法去加载npm模块。

当然我们这里不得不说的是,ES2015(ES6)里也有了自己的模块机制,也就是说ES6的模块机制是官方规定的,我们通过 babel (一种6to5的编译器)可以使用比较多的新特性了,包括我们提到的模块机制,而它的写法大致如下:

import {someModule} from "someModule";

// your codes...

export anotherModule;

当然上面的写法只是最基本的,还有其他的不同加载模块的写法,可以看一下阮一峰老师的 ECMAScript 6 入门 或者babel的相关文档 Learn ES2015 。

功能特性

browserify的出现非常棒,但webpack更胜一筹!

我们来看看webpack支持哪些功能特性:

  1. 支持CommonJs和AMD模块,意思也就是我们基本可以无痛迁移旧项目。
  2. 支持模块加载器和插件机制,可对模块灵活定制。特别是我最爱的babel-loader,有效支持ES6。
  3. 可以通过配置,打包成多个文件。有效利用浏览器的缓存功能提升性能。
  4. 将样式文件和图片等静态资源也可视为模块进行打包。配合loader加载器,可以支持sass,less等CSS预处理器。
  5. 内置有source map,即使打包在一起依旧方便调试。

看完上面这些,可以想象它就是一个前端工具,可以让我们进行各种模块加载,预处理后,再打包。之前我们对这些的处理是放在grunt或gulp等前端自动化工具中。有了webpack,我们无需借助自动化工具对模块进行各种处理,让我们工具的任务分的更加清晰。

我们看一下官方对webpack理解的图。

任何静态资源都可以视作模块,然后模块之间也可以相互依赖,通过webpack对模块进行处理后,可以打包成我们想要的静态资源。

既然已经大致知道为什么我们要使用webpack了,我们接下来就开始使用webpack吧!

#开始使用webpack

首先新建一个webpack101的项目,我们将在webpack101这里开展我们接下来的各项学习。

$ npm init // 用于初始化项目的package.json

//初始化文件目录:
webpack101
  --- src
    --- entry.js
    --- module1.js
  --- index.html
  --- package.json
  --- webpack.config.js

安装webpack

我们通过npm来将webpack安装到全局

$ npm install webpack -g

一个最简单的webpack

webpack配置

webpack是需要进行配置的,我们在使用webpack的时候,会默认 webpack.config.js 为我们的配置文件。所以接下来,我们新建这个js文件。

// webpack.config.js
var path = require("path");
module.exports = {
  entry: '../src/entry.js', //演示单入口文件
  output: {
    path: path.join(__dirname, 'out'),  //打包输出的路径
    filename: 'bundle.js',			  //打包后的名字
    publicPath: "./out/"				//html引用路径,在这里是本地地址。
  }
};

编写入口文件

接下来就编写我们的入口文件 entry.js 和第一个模块文件 module1.js 。我们一切从简,里面只用来加载一个Js模块。

// entry.js
require("./module1"); // 使用CommonJs来加载模块

下一个文件

// module1.js
console.log("Hello Webpack!");

启动webpack

一切准备好后,我们仅需要在项目根目录下,用命令行 webpack 执行一下即可。

// webpack 命令行的几种基本命令

$ webpack // 最基本的启动webpack方法
$ webpack -w // 提供watch方法,实时进行打包更新
$ webpack -p // 对打包后的文件进行压缩,提供production
$ webpack -d // 提供source map,方便调试。

webpack成功运行后,我们就可以看到根目录出现了out文件夹,里面有我们打包生成的 bundle.js 。我们最后通过在 index.html 里对这个文件引入就可以了。我们可以在控制台看到我们想要的结果, Hello Webpack !

多模块依赖

刚才的例子,我们仅仅是跑通了webpack通过 entry.js 入口文件进行打包的例子。下面我们就来看一下它是否真的支持CommonJs和AMD两种模块机制呢?下面我们新建多几个js文件吧!

// 修改module1.js
require(["./module3"], function(){
  console.log("Hello Webpack!");
});

下一个文件

// module2.js,使用的是CommonJs机制导出包
module.exports = function(a, b){
  return a + b;
}

下一个文件

// module3.js,使用AMD模块机制
define(['./module2.js'], function(sum){
  return console.log("1 + 2 = " + sum(1, 2));
})

其实像上面这样混用两种不同机制非常不好,这里仅仅是展示用的,在开发新项目时还是推荐CommonJs或ES2015的Module。当然我个人更倾向于ES2015的模块机制的~

loader加载器

到了我最喜欢也是最激动人心的功能了!我们先想想应用场景,前端社区有许多预处理器供我们使用。我们可以使用这些预处理器做一些强大的事情,大家都听过的就是 CoffeeScript 和 Sass 了。我们以前要编译这些预处理器,就是用 gulp 进行编译。但是我们对这些文件处理其实也挺繁琐的,webpack可以一次性解决!

在这里我们用Sass和babel编译ES2015为例子,看一下loader是如何使用的。

安装loader

我们第一步就是先要安装好各个必须的loader,我们直接看看需要通过npm安装什么。

$ npm install style-loader css-loader url-loader babel-loader sass-loader file-loader --save-dev

配置loader

安装完各个loader后,我们就需要配置一下我们的 webpack.config.js ,载入我们的loader。

// webpack.config.js
module.exports = {
  entry: path.join(__dirname, 'src/entry.js'),
  output: {
    path: path.join(__dirname, 'out'),
    publicPath: "./out/",
    filename: 'bundle.js'
  },
  // 新添加的module属性
  module: {
    loaders: [
      {test: /\.js$/, loader: "babel"},
      {test: /\.css$/, loader: "style!css"},
      {test: /\.(jpg|png)$/, loader: "url?limit=8192"},
      {test: /\.scss$/, loader: "style!css!sass"}
    ]
  }
};

我们主要看看module的loaders。loaders是一个数组,里面的每一个对象都用正则表达式,对应着一种配对方案。比如匹配到js后缀名就用babel-loader,匹配到scss后缀名的就先用sass,再用css,最后用style处理,不同的处理器通过 ! 分隔并串联起来。这里的loader是可以省略掉 -loader 这样的,也就是原本应该写成 style-loader!css-loader!sass-loader ,当然我们必须惜字如金,所以都去掉后面的东东。

我们仅仅是配置一下,已经是可以直接用ES2015和SASS去写我们的前端代码了。在此之前,我们对src文件夹里再细分成js,css,image三个文件夹,处理好分层。话不多说,赶紧试试。

稍微复杂的webpack项目

bebel-loader

// js/es6-module.js
class People{
  constructor(name){
    this.name = name;
  }
  sayhi(){
    console.log(`hi ${this.name} !`);
  }
}
exports.module = People;

写好模块后,我们直接在 entry.js 入口文件中引入该模块。

// entry.js

// javascript
require('./js/module1');
let People = require('./js/es6-module');
let p = new People("Yika");
p.sayHi();

// css
require('./css/main.scss');

哈哈哈,不能再爽!这下子我们可以使用很多优秀的ES6特性去构建大型的web了。

sass-loader

大家或许注意到了下方的css的require,那就是用来加载Sass样式的。我们通过启动style-loader会将css代码转化到 <style> 标签内,我们看一下里面的内容。

// css/main.scss
html, body{
  background: #dfdfdf;
}

最后我们打开 index.html 观察我们所有的结果,首先背景已经是淡灰色的,并且控制台也有我们想要的内容。我们通过查看DOM结构,可以发现 head 标签里多出了 style 标签,里面正是我们想要定制的样式。

关于对图片的打包

我们之前也说,webpack对与静态资源来说,也是看作模块来加载的。CSS我们是已经看过了,那图片是怎么作为模块打包加载进来呢?这里我们可以想到,图片我们是用url-loader加载的。我们在css文件里的url属性,其实就是一种封装处理过require操作。当然我们还有一种方式就是直接对元素的src属性进行require赋值。

div.img{
  background: url(../image/xxx.jpg)
}

//或者
var img = document.createElement("img");
img.src = require("../image/xxx.jpg");
document.body.appendChild(img);

上述两种方法都会对符合要求的图片进行处理。而要求就是在url-loader后面通过query参数的方式实现的,这里就是说只有不大于8kb的图片才会打包处理成Base64的图片。关于query,请看文档: Query parameters

{test: /\.(jpg|png)$/, loader: "url?limit=8192"}

打包成多个资源文件

我们在开发多页面的站点的时候,还是需要希望能有多个资源文件的。这样我们就可以有效利用缓存提升性能,做到文件按需加载。如何写入口文件,这里就不再赘述了,我们直接看如何对 webpack.config.js 进行修改。

// webpack.config.js

entry: {
  page1: "entry.js",
  page2: "entry2.js"
},
output: {
  path: path.join(__dirname, 'out'),
    publicPath: "./out/",
    filename: '[name].js'
}

这里重点关注两个地方,entry属性可以是一个对象,而对象名也就是key会作为下面output的filename属性的 [name] 。当然entry也可以是一个数组,更多用法都可以去webpack的 官方文档 进行查看。

当然webpack也考虑到公共模块的利用,我们利用插件就可以智能提取公共部分,以提供我们浏览器的缓存复用。我们只需要在 webpack.config.js 添加下面的代码即可。

// 修改添加,webpack.config.js
var webpack = require('webpack');
module.exports = {
  // ....省略各种代码
      plugins: [
        new webpack.optimize.CommonsChunkPlugin('common.js')
      ]
}

我们做个小测试,让第二个入口文件也加载我们之前的 es6-module.js 。然后我们用webpack进行打包,就发现生成的 common.js 里是有相应代码的。我们需要手动在html上去加载 common.js ,并且是 必须要最先加载 。

独立出css样式

如果我们希望样式通过 <link> 引入,而不是放在 <style> 标签内呢,即使这样做会多一个请求。这个时候我们就要配合插件一起使用啦,我们一起来看看。

$ npm install extract-text-webpack-plugin --save-dev

安装完插件就要配置 webpack.config.js 了。我们添加以下代码

var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
  // ...省略各种代码
  module: {
    loaders: [
      {test: /\.js$/, loader: "babel"},
      {test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader")},
      {test: /\.(jpg|png|svg)$/, loader: "url?limit=8192"},
      {test: /\.scss$/, loader: "style!css!sass"}
    ]
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin('common.js'),
    new ExtractTextPlugin("[name].css")
  ]
}

为了区分开用 <link> 链接和用 <style> ,我们这里以CSS后缀结尾的模块用插件。我们重点关注一下使用了ExtractTextPlugin的模块,在ExtractTextPlugin的extract方法有两个参数,第一个参数是经过编译后通过style-loader单独提取出文件来,而第二个参数就是用来编译代码的loader。

当然,插件也支持所有独立样式打包成一个css文件。增加多一个参数即可。

new ExtractTextPlugin("style.css", {allChunks: true})

至于怎样加载样式是最佳实践,这个就要自己平时多思考了。多站点多样式的时候,是做到一次性打包加载呢,还是按需加载呢?我这里就建议一项,主页尽量做到最精简,毕竟决定用户存留时间。

#总结

前端社区不断发展,越来越趋向于组件化的发展。通过webpack,我们就能体验到one component one module 的开发感觉。当然如何更好的使用webpack还是要通过不断的思考总结,才能找到最优的方案。

 

 

 

 

 

 

 

posted @ 2016-10-16 23:23  最骚的就是你  阅读(1073)  评论(1编辑  收藏  举报