• 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{
    	 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还是要通过不断的思考总结,才能找到最优的方案。

     

  • 相关阅读:
    OCP-1Z0-051-V9.02-80题
    OCP-1Z0-051-V9.02-124题
    Flex中的HDividedBox和VDividedBox的比较
    Flex中AdvancedDataGrid的用法
    IDA,很好很强大
    AndroidManifest.xml文件中加入文件控制控制权限
    OCP-1Z0-051-V9.02-6题
    OCP-1Z0-051-V9.02-5题
    OCP-1Z0-051-V9.02-4题
    Android Eclipse JNI 调用 .so文件加载问题
  • 原文地址:https://www.cnblogs.com/libin-1/p/5968188.html
Copyright © 2020-2023  润新知