zoukankan      html  css  js  c++  java
  • Webpack 配置示例

    Webpack 作为前端构建工具,对于大型网站开发,大大提升了开发效率。要使用webpack需要先安装webpack工具;

    先来看一个最简单的命令

    $ webpack main.js bundle.js

    该命令将 main.js 输出到 bundle.js 。

    通常,都不会这样直接使用使用,而是在项目根目录下进行打包配置,配置文件默认为webpack.config.js。

    // webpack.config.js
    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      }
    };

    之后,直接在命令行中使用 webpack 就能进行打包了!

    除了直接使用 webpack 进行打包之外,还可以对打包命令进行一些选择性的配置:

    • webpack – for building once for development
    • webpack -p – for building once for production (minification)
    • webpack --watch – for continuous incremental build
    • webpack -d – to include source maps
    • webpack --colors – for making things pretty

    同样,这些配置也可以写进 package.json 配置文件中

    // package.json
    {
      // ...
      "scripts": {
        "dev": "webpack-dev-server --devtool eval --progress --colors",
        "deploy": "NODE_ENV=production webpack -p"
      },
      // ...
    }

    1. entry

    // webpack.config.js
    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      }
    };

    entry 除了使用一个单一的 js 文件之外,还可以使用多个 js 文件;

    module.exports = {
      entry: {
        bundle1: './main1.js',
        bundle2: './main2.js'
      },
      output: {
        filename: '[name].js'
      }
    };

    2. Babel-loader

    Loader 是源代码转换预处理器(more info). 例如, Babel-loader 可以将 JSX/ES6 转换成 JS 文件. 参见官方文档:loaders.

    // main.jsx is a JSX file.
    
    const React = require('react');
    const ReactDOM = require('react-dom');
    
    ReactDOM.render(
      <h1>Hello, world!</h1>,
      document.querySelector('#wrapper')
    );

    index.html

    <html>
      <body>
        <div id="wrapper"></div>
        <script src="bundle.js"></script>
      </body>
    </html>

    webpack.config.js

    module.exports = {
      entry: './main.jsx',
      output: {
        filename: 'bundle.js'
      },
      module: {
        loaders:[
          {
            test: /.js[x]?$/,
            exclude: /node_modules/,
            loader: 'babel-loader?presets[]=es2015&presets[]=react'
          },
        ]
      }
    };

    module.loaders 用于指定 loaders. 上面的代码片段使用了 babel-loader,也用到了babel-preset-es2015babel-preset-react 用来转换 ES6 和 React。也可以使用如下的query的方式来配置:

    module: {
      loaders: [
        {
          test: /.jsx?$/,
          exclude: /node_modules/,
          loader: 'babel',
          query: {
            presets: ['es2015', 'react']
          }
        }
      ]
    }

    3. CSS-loader

    Webpack 使我们可以通过 require 引用一个css文件并结合css-loader处理之后输出成一个模块。

    main.js

    require('./app.css');

    app.css

    body {
      background-color: blue;
    }

    index.html

    <html>
      <head>
        <script type="text/javascript" src="bundle.js"></script>
      </head>
      <body>
        <h1>Hello World</h1>
      </body>
    </html>

    webpack.config.js

    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      },
      module: {
        loaders:[
          { test: /.css$/, loader: 'style-loader!css-loader?modules' },
        ]
      }
    };

    注意,这里使用了两个loader来转换css文件。 CSS-loader 用来读取CSS文件, Style-loader用来插入样式到网页中. 不同的loader用 ! 来连接.

    在浏览器中浏览网页,index.html中已经插入了样式表。

    <head>
      <script type="text/javascript" src="bundle.js"></script>
      <style type="text/css">
        body {
          background-color: blue;
        }
      </style>
    </head>

    4. Image loader

    Webpack 还可以通过 require 引用图片文件。

    main.js

    var img1 = document.createElement("img");
    img1.src = require("./small.png");
    document.body.appendChild(img1);
    
    var img2 = document.createElement("img");
    img2.src = require("./big.png");
    document.body.appendChild(img2);

    index.html

    <html>
      <body>
        <script type="text/javascript" src="bundle.js"></script>
      </body>
    </html>

    webpack.config.js

    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      },
      module: {
        loaders:[
          { test: /.(png|jpg)$/, loader: 'url-loader?limit=8192' }
        ]
      }
    };

    这里使用了 url-loader 来转换图片文件. 如果图片小于 8192 bytes 将会被转换成 Data URL; 否则将会被转换成普通的URL. ? 用来给url-loader传入参数.

    两张不同大小的图片会被转换成不同的格式如下:

    <img src="data:image/png;base64,iVBOR...uQmCC">
    <img src="4853ca667a2b8b8844eb2693ac1b2578.png">

    5. CSS Module

    css-loader?modules 表示打开 CSS Modules 的功能。它表示module中定义的css样式默认是局部作用域;如果需要转换成全局作用域可以通过 :global(.abc) (more info)

    index.html

    <html>
    <body>
      <h1 class="h1">Hello World</h1>
      <h2 class="h2">Hello Webpack</h2>
      <div id="example"></div>
      <script src="./bundle.js"></script>
    </body>
    </html>

    app.css

    .h1 {
      color:red;
    }
    
    :global(.h2) {
      color: blue;
    }

    main.jsx

    var React = require('react');
    var ReactDOM = require('react-dom');
    var style = require('./app.css');
    
    ReactDOM.render(
      <div>
        <h1 className={style.h1}>Hello World</h1>
        <h2 className="h2">Hello Webpack</h2>
      </div>,
      document.getElementById('example')
    );

    webpack.config.js

    module.exports = {
      entry: './main.jsx',
      output: {
        filename: 'bundle.js'
      },
      module: {
        loaders:[
          {
            test: /.js[x]?$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            query: {
              presets: ['es2015', 'react']
            }
          },
          {
            test: /.css$/,
            loader: 'style-loader!css-loader?modules'
          }
        ]
      }
    };

    6. UglifyJs Plugin

    Webpack 有插件支持用来扩展更多的需求。 UglifyJs Plugin 将会最小化输出的js文件.

    main.js

    var longVariableName = 'Hello';
    longVariableName += ' World';
    document.write('<h1>' + longVariableName + '</h1>');

    webpack.config.js

    var webpack = require('webpack');
    var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      },
      plugins: [
        new uglifyJsPlugin({
          compress: {
            warnings: false
          }
        })
      ]
    };

    运行项目,main.js 将被输出成如下格式:

    var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")

    注意:如果需要结合使用到postcss,webpack.config.js文件需要有一些小的修改如下:

    var values = require("postcss-modules-values");
    var webpack = require('webpack');
    var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
    
    module.exports = {
        entry: __dirname + "/index.js",
        output: {
            path:"public",
            publicPath: "/",
            filename: "bundle.js"
        },
        module: {
            loaders:[
                {
                    test: /.js$/,
                    exclude: /node_modules/,
                    loader:'babel-loader'
                },
                {
                    test: /.css$/,
                    loader: "style-loader!css-loader?modules!postcss-loader"
                }
            ]
        },
        plugins:[
            new uglifyJsPlugin({
                compress:{
                    warnings: false
                }
            }),
            new webpack.LoaderOptionsPlugin({
                test:/.css$/,
                options: {
                    postcss:[values]
                }
            })
        ]
    };
    View Code

    备注: UglifyJsPlugin还可以对一些指定的变量不进行混淆

    plugins: [
      new webpack.optimize.UglifyJsPlugin({
        mangle: {
          except: ['$super', '$', 'exports', 'require']
          //以上变量‘$super’, ‘$’, ‘exports’ or ‘require’,不会被混淆
        },
        compress: {
          warnings: false
        }
      })
    ]

    7. HTML Webpack Plugin and Open Browser Webpack Plugin

    下面来看如何加载第三方插件

    html-webpack-plugin 可以创建index.html, open-browser-webpack-plugin 可以打开一个浏览器窗口当 Webpack 加载完成之后。
    npm install html-webpack-plugin open-browser-webpack-plugin webpack-dev-server --save

    main.js

    document.write('<h1>Hello World</h1>');

    webpack.config.js

    var HtmlwebpackPlugin = require('html-webpack-plugin');
    var OpenBrowserPlugin = require('open-browser-webpack-plugin');
    
    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      },
      plugins: [
        new HtmlwebpackPlugin({
          title: 'Webpack-demos',
          filename: 'index.html'
        }),
        new OpenBrowserPlugin({
          url: 'http://localhost:8080'
        })
      ]
    };

    运行 webpack-dev-server.

    $ webpack-dev-server

    现在不需要手动创建index.html文件,也不需要去打开浏览器窗口了,一切由webpack为我们包办了!

    可能遇到的错误: Error: Cannot find module 'webpack/lib/node/NodeTemplatePlugin' ,解决办法:在项目中重新安装webpack。

    8. Environment flags

    可以通过一些配置来对开发环境和正式环境进行一些不同的操作;

    main.js

    document.write('<h1>Hello World</h1>');
    
    if (__DEV__) {
      document.write(new Date());
    }

    webpack.config.js

    var webpack = require('webpack');
    
    var devFlagPlugin = new webpack.DefinePlugin({
      __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
    });
    
    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      },
      plugins: [devFlagPlugin]
    };

    运行webpack打包并输入环境变量配置:

    # Linux & Mac
    $ env DEBUG=true webpack-dev-server
    
    # Windows
    $ set DEBUG=true
    $ webpack-dev-server

    process.env 默认为一个空对象,通过 env DEBUG=true命令 为env.DEBUG赋值。

    9. Code splitting

    对于大型web网站,不可能将所有的js文件都放到一个文件中一次性加载, Webpack 允许我们将js文件进行分割。

    首先,你需要使用 require.ensure 来定义分割点 (official document)

    // main.js
    require.ensure(['./a'], function(require) {
      var content = require('./a');
      document.open();
      document.write('<h1>' + content + '</h1>');
      document.close();
    });

    require.ensure 告诉 Webpack,./a.js 文件应该从bundle.js文件中分割出来并编译到一个单独的文件中。

    // a.js
    module.exports = 'Hello World';

    现在webpack将会自动进行编译打包,不需要再进行额外的配置。

    webpack.config.js

    module.exports = {
      entry: './main.js',
      output: {
        filename: 'bundle.js'
      }
    };
    从表象上看,没有任区别,但实际上webpack将main.js和a.js编译到两个不同的文件中了,分别是bundle.js和1.bundle.js文件,当需要用到的时候再加载1.bundle.js文件;

    10. Code splitting with bundle-loader

    另一个代码分割的方法是使用 bundle-loader.

    // main.js
    
    // Now a.js is requested, it will be bundled into another file
    var load = require('bundle-loader!./a.js');
    
    // To wait until a.js is available (and get the exports)
    //  you need to async wait for it.
    load(function(file) {
      document.open();
      document.write('<h1>' + file + '</h1>');
      document.close();
    });

    require('bundle-loader!./a.js') 告诉 Webpack 需要从另外的js文件中去加载 a.js。webpack的行为将和上面相同。

    11. Common chunk

    当多个script文件需要使用到相同的chunk的时候,可以将这个公用的模块通过CommonsChunkPlugin提取到单独的文件中。

    // JQ01.js
    var $ = require("jquery");
    $('#a').text("001");
    
    // JQ02.js
    var $ = require("jquery");
    $('#b').text("002");

    上面的两个不同的组件中,都同时需要用到 JQuery,甚至会有更多的组件也会如此,此时可以将 JQuery 提取出来,放置到一个公共的 js 文件中。

    index.html

    <html>
      <body>
        <div id="a"></div>
        <div id="b"></div>
        <script src="vendor.js"></script>
        <script src="bundle1.js"></script>
        <script src="bundle2.js"></script>
      </body>
    </html>

    webpack.config.js

    var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
    
    module.exports = {
        entry: {
            bundle1: "./JQ01.js",
            bundle2: "./JQ02.js",
            vendor: ["jquery"] // option
        },
        output: {
            filename: "[name].js"
        },
        plugins: [
            new CommonsChunkPlugin({
                name: 'vendor',
                filename: "vendor.js"
            })
        ]
    };

    随着库越来越大,vendor文件也变得越来越大,于是考虑打包成两个vendor,把和react相关的库打包成一个vendor,其他的库打包成另外一个vendor。

    ...
    entry: { 
        "vendor1": ["react", "react-dom", "react-router", "react-router-redux", "react-redux", "redux"], 
        "vendor2": ["jquery"],
        "app": "./js/index.js" 
    },
    ...
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            names: ["vendor2", "vendor1"],
            minChunks: Infinity
        })
    ],
    ...

    有两个需要注意的地方:

    • 在CommonsChunkPlugin里面,vender的顺序要反着来,要和加载顺序相反。比如你想按vendor1,vendor2的顺序加载,entry里面写的是vendor1,vendor2,在CommonsChunkPlugin里面要写vendor2,vendor1。
    • output.filename一定不要写死了,要配置成可替换的,类似filename: '[name].js'形式。

    12. Vendor chunk

    也可以通过 CommonsChunkPlugin 来分割提取出js库。

    main.js

    var $ = require('jquery');
    $('h1').text('Hello World');

    index.html

    <html>
      <body>
        <h1></h1>
        <script src="vendor.js"></script>
        <script src="bundle.js"></script>
      </body>
    </html>
    View Code

    webpack.config.js

    var webpack = require('webpack');
    
    module.exports = {
      entry: {
        app: './main.js',
        vendor: ['jquery'],
      },
      output: {
        filename: 'bundle.js'
      },
      plugins: [
        new CommonsChunkPlugin({
          name: 'vendor', 
          filename: "vendor.js"})
      ]
    };
    View Code

    ProvidePlugin

    
    

    如果你希望一个module可以作为一个变量使用到其它地方,比如使用jQuery的 $ ,我们可以在任何地方使用而不需要通过 require("jquery"),这就需要用到 ProvidePlugin (Official doc).

    // main.js
    $('h1').text('Hello World');

    webpack.config.js

    var webpack = require('webpack');
    
    module.exports = {
      entry: {
        app: './main.js'
      },
      output: {
        filename: 'bundle.js'
      },
      plugins: [
        new webpack.ProvidePlugin({
          $: "jquery",
          jQuery: "jquery",
          "window.jQuery": "jquery"
        })
      ]
    };

    13. Exposing global variables

    如果我们想使用一些全局变量,但又不想把它们包含在webpack中,这时候可以通过在webpack.config.js中 配置 externals 来实现 official document

    data.js.

    var data = 'Hello World';

    将data数据暴露成全局变量

    // webpack.config.js
    module.exports = {
      entry: './main.jsx',
      output: {
        filename: 'bundle.js'
      },
      module: {
        loaders:[
          {
            test: /.js[x]?$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            query: {
              presets: ['es2015', 'react']
            }
          },
        ]
      },
      externals: {
        // require('data') is external and available
        //  on the global var data
        'data': 'data'
      }
    };

    现在,通过 var data = require('data') 可以将data.js输出到模块变量中。但实际上data是一个全局变量。

    // main.jsx
    var data = require('data');
    var React = require('react');
    var ReactDOM = require('react-dom');
    
    ReactDOM.render(
      <h1>{data}</h1>,
      document.body
    );

    14. Hot Module Replacement

    Hot Module Replacement (HMR) 当网页发生改变的时候,不需要手动刷新页面。结合webpack-dev-server有两种方式来打开 HMR。

    (1) 在命令中指定 --hot 和 --inline

    $ webpack-dev-server --hot --inline

    Meaning of the options:

    • --hot: adds the HotModuleReplacementPlugin and switch the server to hot mode.
    • --inline: embed the webpack-dev-server runtime into the bundle.
    • --hot --inline: also adds the webpack/hot/dev-server entry.

    (2) 配置 webpack.config.js.

    • add new webpack.HotModuleReplacementPlugin() to the plugins field
    • add webpack/hot/dev-server and webpack-dev-server/client?http://localhost:8080 to the entry field

    webpack.config.js

    var webpack = require('webpack');
    var path = require('path');
    
    module.exports = {
      entry: [
        'webpack/hot/dev-server',
        'webpack-dev-server/client?http://localhost:8080',
        './index.js'
      ],
      output: {
        filename: 'bundle.js',
        publicPath: '/static/'
      },
      plugins: [
        new webpack.HotModuleReplacementPlugin()
      ],
      module: {
        loaders: [{
          test: /.jsx?$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          query: {
            presets: ['es2015', 'react']
          },
          include: path.join(__dirname, '.')
        }]
      }
    };
    Now launch the dev server.
    $ webpack-dev-server

    在浏览器中打开 http://localhost:8080 查看网页。保持网页打开,对网页修改一些内容,观察浏览器是否发生改变;

    App.js

    import React, { Component } from 'react';
    
    export default class App extends Component {
      render() {
        return (
          <h1>Hello World</h1>
        );
      }
    }

    index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    
    ReactDOM.render(<App />, document.getElementById('root'));

    index.html

    <html>
      <body>
        <div id='root'></div>
        <script src="/static/bundle.js"></script>
      </body>
    </html>

    15. React router

    参考 React-router 官方示例

    +---------------------------------------------------------+
    | +---------+ +-------+ +--------+                        |
    | |Dashboard| | Inbox | |Calendar|      Logged in as Jane |
    | +---------+ +-------+ +--------+                        |
    +---------------------------------------------------------+
    
    $ webpack-dev-server --history-api-fallback 

     参考连接:

     Webpack 官方文档 : http://webpack.github.io/docs/configuration.html

  • 相关阅读:
    能量项链
    开学前最后一天信奥赛一本通重刷日记
    重刷信奥赛一本通日记-3
    重刷信奥赛一本通日记-2
    重刷信奥赛一本通日记-1
    第二次考试题解way
    第一次考试题解
    第一次考试感言
    「HNOI2012」矿场搭建
    「HAOI2006」受欢迎的牛
  • 原文地址:https://www.cnblogs.com/284628487a/p/6365801.html
Copyright © 2011-2022 走看看