Webpack

Starter

Webpack is a front-end build systems like Grunt and Gulp.It can be used as a module bundler similar to Browserify, and do much more.

A module bundler 模块打包工具(打包成较小/少的文件) Module:can be CommonJS,AMD,ES6 modules,images,json,coffeescript,less,...and custom stuff. 任何一个静态的资源都可以视为一个module,被引用;还可整合第三方的类库,也视为module,在项目中引用

特性:

  • code spliting :代码分割,只加载需要的文件(切分依赖树,分到不同代码块,然后按需加载这些依赖,减少初始化时间,类似懒加载)
  • loader :各module通过对应的loader处理
  • plugin system :插件系统,eg:模块热更新

安装:

npm install webpack -g

Hello World

  1. hello.js

     require('./world.js');        // CommonJS模块化方式
     /*
         1. style-loader 对css-loader处理完的文件通过<style>标签插入html
         2. css-loader 使得webpack可以处理.css文件
         3. 或者直接 require('./style.css'),执行webpack命令时使用module-bind
         eg: webpack hello.js hello.boundle.js --module-bind 'css=style-loader!css-loader'
     */
     require('style-loader!css-loader!./style.css'); 
    
     function hello(str){
         alert(str);
     }
     hello("Hello world");    // 执行
    
  2. world.js

     function world(){
         return {};
     }
    
  3. style.css

     html,body{
         padding: 0;
         margin: 0;
     }
     body{
         background:#eee;
     }
    
  4. 执行

     > npm install css-loader style-loader --save-dev
     > webpack hello.js hello.boundle.js
    
     # 若直接 require('./style.css'),执行webpack命令时使用module-bind
     > webpack hello.js hello.boundle.js --module-bind 'css=style-loader!css-loader' --watch
    
    • --watch 文件改变时自动更新打包
    • --progress 显示打包过程
    • --display-modules 列出打包的模块
    • --display-reasons 列出打包模块的原因
  5. 使用打包的js:index.html

     <!DOCTYPE html>
     <html>
         <head>
             <meta charset="utf-8">
             <title>webpack test</title>
         </head>
         <body>
             <script type="text/javascript" src="hello.boundle.js"/>
         </body>
     </html>
    

webpack.config.js

webpack配置文件, Refer Configuration

  1. src/script/main.js

     function hello(){
         alert("Hello world");
     }
    
  2. index.html

     <script type="text/javascript" src="dist/js/boundle.js"/>
    
  3. webpack.config.js

     module.exports={
         entry:'./src/script/main.js' // 打包入口
         ,output:{                    // 打包结果文件
             path:'./dist/js'
             filename:'boundle.js'
         }
     }
    
  4. 执行

     # 默认会使用webpack.config.js
     > webpack
    
     # 可使用--config指定webpack配置文件
     > mv webpack.config.js webpack.dev.config.js
     > webpack --config webpack.dev.config.js
    
    • 注:可通过npm执行webpack,配置package.json (customize scripts field):
        "scripts":{
            ...
            "webpack":"webpack --config webpack.dev.config.js --progress --display-module --colors"
        }
      
        # 执行
        > npm run webpack
      

输入和输出配置 ( entry & output) :

  1. entry: which Webpack reads to build,could for SPA-one entry point,MPA-multiple entry points

    • SPA: string
    • MPA: array,json (多个chunk)
  2. output:

    • filename: 可使用占位符 (eg: [name],[hash],[chunkhash]-可用于版本管理),防止multiple entry输出相互覆盖
  3. Demo webpack.config.js:

     module.exports={
         // entry:'./src/script/main.js'         // 打包入口
         // entry:['./src/script/main.js','./src/script/a.js']
         entry:{
             main: './src/script/main.js'
             page1: ['./src/script/a.js','./src/script/b.js']
             page2: './src/script/c.js'
         },   
         output:{                                // 打包结果文件
             path:'./dist/js'
             //filename:'boundle.js'
             filename:'[name]-[chunkhash].js'     //chunkhash md5 文件改变后会变化
         }
     }
    

Plugin

html-webpack-plugin

Demo:自动化生成html页面

  1. 安装html-webpack-plugin插件

     > npm install html-webpack-plugin --save-dev
    
  2. 配置插件使用(webpack.config.js)

     var htmlWebpackPlugin = require('html-webpack-plugin');
     module.exports={
         entry:{
             main: './src/script/main.js'
             page1: ['./src/script/a.js','./src/script/b.js']
             page2: './src/script/c.js'
         }    
         ,output:{
             path:'./dist',
             filename:'js/[name]-[chunkhash].js',
             publicPath:'http://cdn.com/'
         }
         ,plugins:[
              new htmlWebpackPlugin({
                 template: 'index.html',
                 filename: 'index.html',    // output html
                 inject: 'head',              // 指定脚本放入的位置,eg: head,body,..,false
                 minify:{                  // 最小化html
                     removeComments:true,
                     collapseWhitespace:true
                 },
                 chunks:['main','page1'], // 可通过chunks/excludeChunks限定引用
                 date: new Date()
             })   
         ]
     }
    
  3. template: index.html (支持EJS模版语言,可获取config中的配置)

     <%= htmlWebpackPlugin.options.date %>
    
     //在html中添加引用生成的js
     <% for(var key in htmlWebpackPlugin.files){%>
         <%=key%>:<%= JSON.stringfy(htmlWebpackPlugin.files[key])%>
     <% } %>
    
     <%=htmlWebpackPlugin.files.chunks.main.entry%>
     <%=htmlWebpackPlugin.files.chunks.page1.entry%>
    
  4. inline直接内嵌js code, 修改template: index.html

     <script type="text/javascript>
         <% compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
     </script>
    

Loaders

编译资源文件的预加载器。在webpack.config.js中,module.loaders领域被用于设定加载器。 注意:处理方式从右到左! Refer Loader

babel-loader

Demo: 使用babel-loader转换ES6语法的代码为浏览器直接可以接受的JS代码

  1. 安装依赖

     npm install babel-loader babel-core --save-dev
     npm install babel-preset-latest --save-dev
    
  2. webpack.config.js

     var path=require('path');
     module.exports={
         ...
         module:{
             loaders:[
                 {
                     test:/\.js$/,
                     exclude:path.resolve(__dirname,"node_module"),
                     include:path.resolve(__dirname,'src'),
                     loader:'babel',
                     query:{presets:['latest']}
                 } 
                 // exclude/include condition  需使用绝对路径
                 // babel参数,例如presets,也可以在.babelrc或package.json中指定
             ]
         }
    
     }
    
  3. 注: 上面babel参数,例如presets,也可以在.babelrc或package.json中指定

    • .babelrc
        {
            presets:['latests']
        }
      
    • package.json
        {
            ...
            "babel":{
                "presets":["latest"]
            }
            ...
        }
      

css-loader & style-loader

  1. 安装

     npm install style-loader css-loader --save-dev
    
  2. webpack.config.js

     module.export={
         ...
         module:{
             loaders:[
                 {...},
                 {
                     test:/\.css$/,
                     loader:'style-loader!css-loader'
                 }
             ]
         }
         ...
     }
    

postcss-loader

  1. 安装

     npm install postcss-loader --save-devnpm install autoprefixer --save-dev
    
  2. webpack.config.js

     module.exports={
         ...
         module:{
             loaders:[
                 {...},
                 {
                     test:/\.css$/,
                     loader:'style-loader!css-loader?importLoaders=1!postcss-loader'
                 }
                 //发现生成的css中,@import的css部分未有postcss,需在css-loader加入importLoaders参数,表示css-loader引入它之后n个loader,这里即引入postcss-loader处理
             ]
         },
         postcss:[
             require('autoprefix')({
                 broswers:['last 5 versions']
             })
         ]
         ...
     }
    
  3. 注:特殊css,有些浏览器可能不支持,或语法不同,需加入浏览器前缀,引入postcss-loader处理,eg:

     .flex-div{
         display:flex;
     }
    

less-loader/sass-loader

npm install less less-loader --save-dev
# npm install sass-loader --save-dev

webpack.config.js:

module.exports={
    ...
    module:{
        loaders:[
            {...},
            {
                test:/\.less$/,
                loader:'style!css!postcss!less'
            },
            // 使用less-loader,可以不给css-loader加入importLoaders,也可使@import的less被postcss处理

           {
                test:/\.sass$/,
                loader:'style!css!postcss!sass'
            }
        ]
    }
    ...    
}

html-loader/ejs-loader

处理模版文件 templating loader,eg: html-loader,ejs-loader,jsx(already include in babel)

  • 方式一:当作一个字符串处理,eg: html-loader 将HMTL模板文件当做一个string输出
  • 方式二:当成一个已经编译好的模版函数,eg:将EJS模板文件当做一个函数输出
  • 注:jsx-loader已被集成到babel工具中,不需要单独安装引入

  • 安装loader

     npm install html-loader --save-dev
     npm install ejs-loader --save-dev
    
  • webpack.config.js:

     module.exports={
         ...
         module:{
             loaders:[
                 {...},
                 {
                     test:/\.html$/,
                     loader:'html-loader'
                 },
                 {
                     test:/\.ejs$/,
                     loader:'ejs-loader'
                 }        
             ]
         }
         ...    
     }
    
  • template: layer.ejs:

     <div>
         <div> This is <%=name%> layer</div>
     </div>
    
  • 执行webpack,会生成layer.js

  • 在app.js中使用: 实现index.html的app节点下下插入模板layer

     import './css/common.css';
     import Layer from './components/layer/layer.js'
    
     const App=function(){
         var dom=document.getElementById('app');
         var layer=new Layer();
         dom.innerHTML=layer.tpl({
             name:'Tom'
         });
     }
     new App();
    

file-loader

文件处理

  1. 安装file-loader

     npm install file-loader --save-dev
    
  2. webpack.config.js, loader:

     {
         test:/\.(png|jpg|gif|svg)$/i,
         loader:'file-loader',
         query:{
             path:'assets/[name]-[hash:5].[ext]'
         } 
     }
    
  3. 注:css/less/html 中引入相对路径的图片都没有问题,会自动替换,但在template文件中,需如下(使用require命令)

     <img src="${require('../../assets/bg.png')}" />
    

url-loader

可设置limit

  • 当文件或图片超过limit,会转换成一个正常的URL引用,eg: <img src="4853ca667a2b8b8844eb2693ac1b2578.png">
  • 当小于limit,会生成base64编码的可直接嵌入的数据,eg:<img src="data:image/png;base64,iVBOR...uQmCC">
npm install url-loader --save-dev

webpack.config.js, loader:

{
    test:/\.(png|jpg|gif|svg)$/i,
    loader:'url-loader',
    query:{
        limit:20000,    // 20k
        path:'assets/[name]-[hash:5].[ext]'
    } 
}

image-webpack-loader

可以压缩图片

npm install image-webpack-loader --save-dev
{
    test:/\.(png|jpg|gif|svg)$/i,
    loader:[
        'url-loader?limit=20000&name=assets/[name]-[hash:5].[ext]',
        'image-webpack'
    ]
   // 处理顺序一样是从右到左,先image loader再url loader

}

优化

  • 开启调试 SourceMap
  • ESLint 检查代码格式
  • 区分开发环境 和 生产环境
  • 使用 middleware 来搭建开发环境
  • Webpack Dev Server,本地 rewrite 规则
  • 代理远程接口
  • 模块热更新
  • Webpack Watch Mode

webpack-dev-server

一个小型的Node Express服务器,为通过wepack打包生成的资源文件提供web服务 功能:

  • 搭建本地服务器
  • 自动刷新

安装:

npm install webpack-dev-server -g

使用: 使用:

> webpack-dev-server

//或启动热加载
> webpack-dev-server --hot --inline

Reference

ruanyf/webpack-demos