• webpack入门和实战(一):webpack配置及技巧


    一、全面理解webpack
    1、什么是 webpack?
    webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图片等都作为模块来使用和处理,它能有Grunt或Gulp所有基本功能。webpack的官网是 https://webpack.github.io/ ,文档地址是https://webpack.github.io/docs,官网对webpack的定义是MODULE BUNDLER,他的目的就是把有依赖关系的各种文件打包成一系列的静态资源。 请看下图:
    2、webpack 的优势
    其优势主要可以归类为如下几个:
    1. webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
    2. 支持很多模块加载器的调用,可以使模块加载器灵活定制,比如babel-loader加载器,该加载器能使我们使用ES6的语法来编写代码;less-loader加载器,可以将less编译成css文件;
    3. 开发便捷,能替代部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等。
    4. 可以通过配置打包成多个文件,有效的利用浏览器的缓存功能提升性能。
    3、wepback它的目标是是什么?
    webpack它能将依赖的模块转化成可以代表这些包的静态文件
    • 将依赖的模块分片化,并且按需加载
    • 解决大型项目初始化加载慢的问题
    • 每一个静态文件都可以看成一个模块
    • 可以整合第三方库
    • 能够在大型项目中运用
    • 可以自定义切割模块的方式

    4、webpack较之其他类似工具有什么不同?

    • 有同步和异步两种不同的加载方式
    • Loader,加载器可以将其他资源整合到JS文件中,通过这种方式,可以讲所有的源文件形成一个模块
    • 优秀的语法分析能力,支持 CommonJs AMD 规范
    • 有丰富的开源插件库,可以根据自己的需求自定义webpack的配置

    5、webpack为什么要将所有资源放在一个文件里面?

    我们知道,对于浏览器来说,加载的资源越少,响应的速度也就越快,所以有时候我们为了优化浏览器的性能,会尽可能的将资源合并到一个主文件app.js里面。但是这导致的很大的缺点:

    • 当你的项目十分庞大的时候,不同的页面不能做到按需加载,而是将所有的资源一并加载,耗费时间长,性能降低。
    • 会导致依赖库之间关系的混乱,特别是大型项目时,会变得难以维护和跟踪。比如:哪些文件是需要A模块加载完后才能执行的?哪些页面会受到多个样式表同时影响的? 等许多问题。

    而webpack可以很好的解决以上缺点,因为它是一个十分聪明的模块打包系统,当你正确配置后,它会比你想象中的更强大,更优秀。

    二、开启wbpack之旅
    安装步骤如下:

    1、生成package.json文件;

    先装好node和npm,因为webpack是一个基于node的项目。然后首先我们需要在根目录下生成package.json文件,需要进入项目文件内根目录下执行如下命令:npm init

    如上通过一问一答的方式后会在根目录下生成package.json文件,如下所示:

    2 . 通过全局安装webpack
    执行命令如下:npm install -g webpack 如下所示:
    在c盘下会生成node_modules文件夹中会包含webpack,此时此刻我们可以使用webpack命令了;
    在常规项目中把webpack依赖加入到package.json
    npm init npm install webpack --save
    更详尽的安装方法个可以参考webpack安装
    3. 配置webpack
    每个目录下都必须有一个webpack.config.js,它的作用就好比Gulpfile.js、或者 Gruntfile.js,就是一个项目配置,告诉webpack需要做什么。
    首先先贴上一个比较完整的webpack.config.js的代码,再详细介绍:
    //详细的webpack.config.js结构分析:
    var path = require('path');
    var webpack = require('webpack');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var TransferWebpackPlugin = require('transfer-webpack-plugin');
    
    module.exports = {
        devtool: 'source-map',//由于打包后的代码是合并以后的代码,不利于排错和定位,只需要在config中添加,这样出错以后就会采用source-map的形式直接显示你出错代码的位置。
        //noParse:[/jquery/],//表示跳过jquery,不对其进行编译,这样可以提高打包的速度
        //页面入口文件配置
        entry: {
            page1: "./src/index.js",
            //page2: ["./src/index.js", "./src/main.js"],支持数组形式,将加载数组中的所有模块,但以最后一个模块作为输出
        },
        //入口文件输出配置
        output: {
            path: "dist/js/page",
            filename: "[name].bundle.js",// page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夹下。
            publicPath: "/dist/"	//网站运行时的访问路径。
        },
        resolveLoader: {
            //指定默认的loader路径,否则依赖走到上游会找不到loader
            root: path.join(__dirname, 'node_modules'),
            alias: {//给自己写的loader设置别名
                "seajs-loader": path.resolve( __dirname, "./web_modules/seajs-loader.js" )
            }
        },
        //新建一个开发服务器,并且当代码更新的时候自动刷新浏览器。
        devServer: {
            historyApiFallback: true,
            noInfo: true,
            hot: true,
            inline: true,
            progress: true,
            port:9090 //端口你可以自定义
        },
        module: {
            // module.loaders 是最关键的一块配置。它告知 webpack每一种文件都需要使用什么加载器来处理:
            loaders: [
            { test: /.css$/, loader: 'style-loader!css-loader' },//.css 文件使用 style-loader 和 css-loader 来处理.
            //{ test: /.css$/, loader: 'style!css' },其他写法1、"-loader"其实是可以省略不写的,多个loader之间用“!”连接起来。
            //{ test: /.css$/, loaders: ["style", "css"] },其他写法2、用loaders数组形式;
            //.scss 文件使用 style-loader、css-loader 和 sass-loader 来编译处理。
            //在chrome中我们通过sourcemap可以直接调试less、sass源文件文件
            { test: /.scss$/, loader: 'style!css!sass?sourceMap'},
            { test: /.less$/, loader: 'style!css!less?sourceMap'},//.less 文件使用 style-loader、css-loader 和 less-loader 来编译处理
            //.js 文件使用babel-loader来编译处理,设置exclude用来排除node_modules这个文件夹中的代码
            { test: /.js$/, loader: 'babel!jsx',exclude: /node_modules/ }, 
            { test: /.jsx$/, loader: "jsx-loader?harmony" },//.jsx 文件使用 jsx-loader 来编译处理
            { test: /.json$/,loader: 'json'},
            //{ test: /.(png|jpg|jpeg|gif)$/, loader: 'url-loader?limit=8192'}, //图片文件使用 url-loader 来处理,小于8kb的直接转为base64
            {test: /.(png|jpg|gif|svg)$/,loader: 'url',
                query: {limit: 10000,name: '[name].[ext]?[hash]'}//设置图片名称扩展名
            },
            { test: /.jade$/, loader: "jade-loader" },//.jade 文件使用 jade-loader 来编译处理
            { test: /.ejs$/, loader: "ejs-loader" },//.ejs 文件使用 ejs-loader 来编译处理 
            { test: /.handlebars$/, loader: "handlebars-loader" },//.handlebars 文件使用handlebars-loader来编译处理handlebars模板文件
            { test: /.dot$/, loader: "dot-loader" },//.dot 文件使用 dot-loader 来编译处理dot模板文件
            { test: /.vue$/, loader: "vue-loader" },//.vue 文件使用 vue-loader 来编译处理
            { test: /.coffee$/, loader: 'coffee-loader' },//.coffee 文件使用 coffee-loader 来编译处理
            { test: /.html$/,loader: 'vue-html'},
            { test: /.woff$/,loader: "url?limit=10000&minetype=application/font-woff"},
            { test: /.ttf$/,loader: "file"},
            { test: /.eot$/,loader: "file"},
            { test: /.svg$/,loader: "file"}
            ]
        },
        //分内置插件和外置插件
        plugins: [
            //使用了一个 CommonsChunkPlugin 的插件,它用于提取多个入口文件的公共脚本部分,然后生成一个common.js来方便多页面之间进行复用。
      		new webpack.optimize.CommonsChunkPlugin('common.js'),
    		new webpack.optimize.UglifyJsPlugin({//压缩文件
    	      compressor: {
    	        warnings: false,//supresses warnings, usually from module minification
    	      },
    	      except: ['$super', '$', 'exports', 'require']    //排除关键字(可选)
    	    }),
    	    new webpack.DefinePlugin({// definePlugin 接收字符串插入到代码当中, 所以你需要的话可以写上 JS 的字符串
                 __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
                 __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
            }),
            new webpack.ProvidePlugin({//把一个全局变量插入到所有的代码中,支持jQuery plugin的使用;使用ProvidePlugin加载使用频率高的模块
                 //provide $, jQuery and window.jQuery to every script
                 $: "jquery",
                 jQuery: "jquery",
                 "window.jQuery": "jquery"
             }),
    	    new webpack.NoErrorsPlugin(), //允许错误不打断程序
    	    new TransferWebpackPlugin([ //把指定文件夹下的文件复制到指定的目录
    	      {from: 'www'}
    	    ], path.resolve(__dirname,"src")),
    	    new HtmlwebpackPlugin({//用于生产符合要求的html文件;
    	       title: 'Hello World app',
               filename: 'assets/admin.html'
    	    })
    	],
        //其它解决方案配置
        resolve: {
            root: 'E:/github/flux-example/src', //绝对路径, 查找module的话从这里开始查找(可选)
            extensions: ['', '.js', '.html', '.css', '.scss'], //自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
            alias: {                            //模块别名定义,方便后续直接引用别名,无须多写长长的地址//后续直接 require('AppStore') 即可
                AppStore : 'js/stores/AppStores.js',
                ActionType : 'js/actions/ActionType.js',
                AppAction : 'js/actions/AppAction.js'
            },
     		modulesDirectories: [//取相对路径,所以比起 root ,所以会多很多路径。查找module(可选)
                 'node_modules',
                 'bower_components',
                 'lib',
                 'src'
            ]
        }
    	
    };
    
    if (process.env.NODE_ENV === 'production') {
      module.exports.devtool = '#source-map'
      // http://vue-loader.vuejs.org/en/workflow/production.html
      module.exports.plugins = (module.exports.plugins || []).concat([
        new webpack.DefinePlugin({
          'process.env': {
            NODE_ENV: '"production"'
          }
        }),
        new webpack.optimize.UglifyJsPlugin({
          compress: {
            warnings: false
          }
        }),
        //为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
        new webpack.optimize.OccurenceOrderPlugin()
      ])
    }

    plugins中包含很多的内置插件和外部插件,它们都有各自的功能,用来处理相关的文件,这里只是罗列了部分,具体用法请看webpack入门和实战(二):全面理解和运用plugins和loader

    就像我在前面提到的,webpack.config.js的写法和在Node里的写法相同,我们主要看的就是文件中的module.exports里面的内容
    • entry 是指入口文件的配置项,它是一个数组的原因是webpack允许多个入口点。
    • output是指输出文件的配置项
      • path - 表示输出文件的路径
      • filename - 表示输出文件的文件名
    • plugins 顾名思义,使用插件可以给webpack添加更多的功能,使webpack更加的灵活和强大,webpack有两种类型的插件:
      • webpack内置的插件
    // 首先要先安装webpack模块
    var webpack = require("webpack");
    module.exports = {
        new webpack.optimize.UglifyJsPlugin({
          compressor: {
            warnings: false,
          },
        })
    };
      •  webpack外置插件
    //npm install component-webpack-plugin 先要在安装该模版
    var ComponentPlugin = require("component-webpack-plugin");
    module.exports = {
        plugins: [
            new ComponentPlugin()
        ]
    }

    更多的插件以及插件的用法,大家可以到webpack的插件上查看。

    • module 配置处理文件的选项
      • loaders 一个含有wepback中能处理不同文件的加载器的数组
        • test 用来匹配相对应文件的正则表达式
        • loaders 告诉webpack要利用哪种加载器来处理test所匹配的文件
      • loaders 的安装方法
            $ npm install xxx-loader --save-dev
    • resolve:其它解决方案配置;
      • resolve.root,绝对路径, 查找module的话从这里开始查找(可选)
      • resolve.modulesDirectories,取相对路径,所以比起 root ,所以会多 parse 很多路径。查找module(可选)
      • resolve.extensions,自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
      • resolve.alias,模块别名定义,方便后续直接引用别名,无须多写长长的地址
    三、利用webpack实现在页面上合理使用打包过后的js文件和图片
    示例如下:
    webpack_test目录结构如下:
    最终完成版的目录结构为:
     index.html代码如下:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>demo1</title>
    </head>
    <body>
        <div id="content"></div>
        <img src="./build/img/demo.png">
        <script src="./build/js/index.js"></script>
    </body>
    </html>

    index.js代码如下:

    require('./index.css');

    index.css代码如下:

    #content{
        121px;
        height:140px;
        background-color: red;
    }
    demo.png自己随便找一张即可;
    根据webpack.config.js的配置情况,操作步骤如下:
    • 全局安装webpack,npm install webpack -g
    • 进入到webpack_test目录下,初始化生成package.json文件,npm init
    • 需要安装的loader有css-loader、style-loader、url-loader,webpack, npm install css-loader style-loader url-loader webpack--save-dev
    • 执行webpack,生成打包过后的build/js/index.js,build/img/demo.png
    • 在index.html中引入即可

    效果如下:

     源码地址为:http://download.csdn.net/detail/wdlhao/9612173,有需要的同学可以自行下载练习;
     四、理解webpack支持commonJS和AMD/CMD两种模块机制进行打包
     1.AMD/CMD模式:
         AMD 规范在这里:https://github.com/amdjs/amdjs-api/wiki/AMD,CMD 规范在这里:https://github.com/seajs/seajs/issues/242
    • AMD(Asynchronous Module Definition) 是 RequireJS 在推广过程中对模块定义的规范化产出。(即RequireJS模块规范)
    RequireJS是一个工具库,主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范(Asynchronous Module Definition)。RequireJS的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。首先,将require.js嵌入网页,然后就能在网页中进行模块化编程了。<script data-main="scripts/main" src="scripts/require.js"></script>上面代码的data-main属性不可省略,用于指定主代码所在的脚本文件,在上例中为scripts子目录下的main.js文件。用户自定义的代码就放在这个main.js文件中。
    • CMD(Common Module Definition )是 SeaJS 在推广过程中对模块定义的规范化产出。(即SeaJS模块规范)
    SeaJS是一个遵循CMD规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制。
    • CommonJS Modules/2.0 规范,是 BravoJS 在推广过程中对模块定义的规范化产出。
    CommonJS API定义很多普通应用程序(主要指非浏览器的应用)使用的API,从而填补了这个空白。它的终极目标是提供一个类似Python,Ruby和Java标准库。这样的话,开发者可以使用CommonJS API编写应用程序,然后这些应用可以运行在不同的JavaScript解释器和不同的主机环境中。在兼容CommonJS的系统中,你可以实用JavaScript程序开发:
    • 服务器端JavaScript应用程序
    • 命令行工具
    • 图形界面应用程序
    • 混合应用程序(如,Titanium或Adobe AIR)

    还有不少⋯⋯这些规范的目的都是为了 JavaScript 的模块化开发,特别是在浏览器端的。目前这些规范的实现都能达成浏览器端模块化开发的目的。

     2、AMD/CMD模式区别

    2.1从官方推荐的写法上面得出:

    CMD ----- 依赖就近

    Js代码 
    //CMD 
    define(function(require,exports,module){ 
       var a = require('./a'); 
       a.doSomthing(); 
    });

    AMD ----- 依赖前置

    Js代码 
    //AMD 
    define(['./a','./b'],function(a,b){ 
    //...... 
    a.doSomthing(); 
    //...... 
    b.doSomthing(); 
    })

    当然AMD也支持CMD的写法。

    2.2、执行顺序上:

      • CMD是延迟执行,推崇的是as lazy as possible
      • AMD是提前执行,requireJS从2.0开始可以延迟执行
    2.3、api设计角度:
      • CMD的API推崇职责单一,没有全局的require
      • AMD的API默认是一个当多个用:比如require有全局的和局部的
     
  • 相关阅读:
    如何成为技术牛人
    重新思考关系型数据库的设计
    架构与管理相通
    传统企业和互联网企业的不同软件价值观
    数据仓库生命周期模型
    用面向对象的思维方式来设计数据库
    数据仓库的几类事实表
    转腾讯产品总监的一篇博文
    开源大数据处理平台简史
    [kuangbin带你飞]专题六 最小生成树 J
  • 原文地址:https://www.cnblogs.com/wdlhao/p/5801918.html
Copyright © 2020-2023  润新知