WebPack 常用功能介绍

发布于 2025-06-09 10:43:02 字数 13954 浏览 1 评论 0

Webpack 是一款用户打包前端模块的工具。主要是用来打包在浏览器端使用的 javascript 的。同时也能转换、捆绑、打包其他的静态资源,包括 css、image、font file、template 等。个人认为它的优点就是易用,而且常用功能基本都有,另外可以通过自己开发 loader 和 plugin 来满足自己的需求。这里就尽量详细的来介绍下一些基本功能的使用。

安装

npm install webpack 

运行 webpack

webpack 需要编写一个 config 文件,然后根据这个文件来执行需要的打包功能。我们现在来编写一个最简单的 config。新建一个文件,命名为 webpack-config.js。config 文件实际上就是一个 Commonjs 的模块。内容如下:

var webpack = require('webpack');
var path = require('path');
var buildPath = path.resolve(__dirname,"build");
var nodemodulesPath = path.resolve(__dirname,'node_modules');

var config = {
    //入口文件配置
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]//当 requrie 的模块找不到时,添加这些后缀
    },
    //文件导出的配置
    output:{
        path:buildPath,
        filename:"app.js"
    }
}

module.exports = config;

我的目录结构是这样的:


webpack
    |---index.html
    |---webpack-config.js
    |---src
         |---main.js
         |---js
              |---a.js

main.js 文件内容如下:


var a = require('./js/a');
a();
console.log('hello world');
document.getElementById("container").innerHTML = "<p>hello world</p>";

a.js 文件内容如下:

module.exports = function(){
    console.log('it is a ');
}

然后我们执行如下的命令:


webpack --config webpack-config.js --colors

这样我们就能在目录里面看到一个新生成的目录 build,目录结构如下:


webpack
    |---index.html
    |---webpack-config.js
    |---build
         |---app.js

然后引用 app.js 就 Ok 啦。main.js 和模块 a.js 的内容就都打包到 app.js 中了。这就演示了一个最简单的把模块的 js 打包到一个文件的过程了。

介绍 webpack config 文件

webpack 是根据 config 里面描述的内容对一个项目进行打包的。接着我们来解释下 config 文件中的节点分别代表什么意思。一个 config 文件,基本都是由以下几个配置项组成的。

entry

配置要打包的文件的入口;可以配置多个入口文件,下面会有介绍。

resolve

配置文件后缀名(extensions),除了 js,还有 jsx、coffee 等等。
alias 配置项,可以为常用模块配置改属性,可以节省编译的搜索时间。例如:

    resolve:{
        extensions:['.js','.jsx'],
        alias:{
            'react':path.join(nodeModulesPath,'react/react.js')
        }
    }

除了这个功能还可以配置其他有用的功能,由于我还不完全了解,有知道的朋友欢迎指教。

output

配置输出文件的路径,文件名等。

module(loaders)

配置要使用的 loader。对文件进行一些相应的处理。比如 babel-loader 可以把 es6 的文件转换成 es5。
大部分的对文件的处理的功能都是通过 loader 实现的。loader 就相当于 gulp 里的 task。loader 可以用来处理在入口文件中 require 的和其他方式引用进来的文件。loader 一般是一个独立的 node 模块,要单独安装。

loader 配置项:

test: /\.(js|jsx)$/,           //注意是正则表达式,不要加引号,匹配要处理的文件
loader: 'eslint-loader',       //要使用的 loader,"-loader"可以省略
include: [path.resolve(__dirname, "src/app")],   //把要处理的目录包括进来
exclude: [nodeModulesPath]     //排除不处理的目录

目前已有的 loader 列表: https://webpack.github.io/docs/list-of-loaders.html

一个 module 的例子:

module: {
    preLoaders: [
      {
        test: /\.(js|jsx)$/,
        loader: 'eslint-loader',
        include: [path.resolve(__dirname, "src/app")],
        exclude: [nodeModulesPath]
      },
    ],
    loaders: [
      {
        test: /\.(js|jsx)$/, //正则表达式匹配 .js 和 .jsx 文件
        loader: 'babel-loader?optional=runtime&stage=0',//对匹配的文件进行处理的 loader 
        exclude: [nodeModulesPath]//排除 node module 中的文件
      }
    ]
}

plugins

顾名思义,就是配置要使用的插件。plugin 是比 loader 功能更强大的插件,能使用更多的 wepack api。来看一个使用 plugin 的例子:

plugins: [
    //压缩打包的文件
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        //supresses warnings, usually from module minification
        warnings: false
      }
    }),
    //允许错误不打断程序
    new webpack.NoErrorsPlugin(),
    //把指定文件夹 xia 的文件复制到指定的目录
    new TransferWebpackPlugin([
      {from: 'www'}
    ], path.resolve(__dirname,"src"))
  ]

目前已有的 plugins 列表: http://webpack.github.io/docs/list-of-plugins.html

如何压缩输出的文件

plugins: [
    //压缩打包的文件
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        //supresses warnings, usually from module minification
        warnings: false
      }
    })]

如何 copy 目录下的文件到输出目录

copy 文件需要通过插件"transfer-webpack-plugin"来完成。

安装:

npm install transfer-webpack-plugin  -save

配置:

var TransferWebpackPlugin = require('transfer-webpack-plugin');
//其他节点省略    
plugins: [
    //把指定文件夹下的文件复制到指定的目录
    new TransferWebpackPlugin([
      {from: 'www'}
    ], path.resolve(__dirname,"src"))
  ]

打包 javascript 模块

支持的 js 模块化方案包括:

  • ES6 模块

    import MyModule from './MyModule.js';
  • CommonJS

    var MyModule = require('./MyModule.js');
  • AMD

    define(['./MyModule.js'], function (MyModule) {
    });

上面已经演示了打包 js 模块,这里不再重复。ES6 的模块需要配置 babel-loader 来先把处理一下 js 文件。
下面展示下打包 ES 模块的配置文件:


var webpack = require('webpack');
var path = require('path');
var buildPath = path.resolve(__dirname, 'build');
var nodeModulesPath = path.resolve(__dirname, 'node_modules');
var TransferWebpackPlugin = require('transfer-webpack-plugin');

var config = {
  entry: [path.join(__dirname, 'src/main.js')],
  resolve: {
    extensions: ["", ".js", ".jsx"]
    //node_modules: ["web_modules", "node_modules"]  (Default Settings)
  },
  output: {
    path: buildPath,    
    filename: 'app.js'  
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new webpack.NoErrorsPlugin(),
    new TransferWebpackPlugin([
      {from: 'www'}
    ], path.resolve(__dirname,"src"))
  ],
  module: {
    preLoaders: [
      {
        test: /\.(js|jsx)$/,
        loader: 'eslint-loader',
        include: [path.resolve(__dirname, "src/app")],
        exclude: [nodeModulesPath]
      },
    ],
    loaders: [
      {
        test: /\.js$/, //注意是正则表达式,不要加引号
        loader: 'babel-loader?optional=runtime&stage=0',//babel 模块相关的功能请自查,这里不做介绍
        exclude: [nodeModulesPath]
      }
    ]
  },
  //Eslint config
  eslint: {
    configFile: '.eslintrc' //Rules for eslint
  },
};

module.exports = config;

打包静态资源

css/sass/less

安装 css-loader 和 style-loader


npm install css-loader --save -dev
npm install style-loader --save -dev

config 配置:


var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[{
            test:/\.css$/,
            loader:'style!css',
            exclude:nodemodulesPath
        }]
    }
}

style-loader 会把 css 文件嵌入到 html 的 style 标签里,css-loader 会把 css 按字符串导出,这两个基本都是组合使用的。打包完成的文件,引用执行后,会发现 css 的内容都插入到了 head 里的一个 style 标签里。
如果是 sass 或 less 配置方式与上面类似。

images

可以通过 url-loader 把较小的图片转换成 base64 的字符串内嵌在生成的文件里。
安装:


npm install url-loader --save -dev

config 配置:

var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[{
            test:/\.css$/,
            loader:'style!css',//
            exclude:nodemodulesPath
        },
        { test:/\.png$/,loader:'url-loader?limit=10000'}//限制大小小于 10k 的
        ]
    }
}

css 文件内容:


#container{
    color: #f00;
    background:url(images/logo-201305.png);
    /*生成完图片会被处理成 base64 的字符串 注意:不要写'/images/logo-201305.png',否则图片不被处理*/
}

iconfont

内嵌 iconfont 的使用方法其实和上述处理 png 图片的方法一致。通过 url-loader 来处理。

config 配置:


var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[{
            test:/\.css$/,
            loader:'style!css',//
            exclude:nodemodulesPath
        },
        { test:/\.(png|woff|svg|ttf|eot)$/,loader:'url-loader?limit=10000'}//限制大小小于 10k 的
        ]
    }
}

css 文件内容:


@font-face {font-family: 'iconfont';
src: url('fonts/iconfont.eot'); /* IE9*/
src: url('fonts/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('fonts/iconfont.woff') format('woff'), /* chrome、firefox */
url('fonts/iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
url('fonts/iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
}

执行打包后会把字体文件都转换成 base64 字符串内容到文件里。
这里有个头疼的问题,就是每个浏览器支持的字体格式不一样,由于把全部格式的字体打包进去,造成不必要的资源浪费。

打包 template

我一大包 handlebars 的模块为例,来演示下打包模块的过程。有的模板对应的 loader,有可能没有现车的,恐怕要自己实现 loader。

先安装必须的 node 模块

npm install handlebars-loader --save -dev
npm install handlebars -save//是必须的

config 配置:


var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[
        { test: /\.html$/, loader: "handlebars-loader" }
        ]
    }
}

新建一个模板文件 tb.html,目录结构:

webpack
    |---index.html
    |---webpack-config.js
    |---src
         |---template
         |         |---tb.html
         |---main.js

main.js 中调用模块的代码如下:


var template = require("./template/tp.html");
var data={say_hello:"it is handlebars"};
var html = template(data);
document.getElementById('tmpl_container').innerHTML = html;         

公用的模块分开打包

这需要通过插件“CommonsChunkPlugin”来实现。这个插件不需要安装,因为 webpack 已经把他包含进去了。
接着我们来看配置文件:

var config = {
    entry:{app:path.resolve(__dirname,'src/main.js'),
            vendor: ["./src/js/common"]},//【1】注意这里
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[{
            test:/\.css$/,
            loader:'style!css',
            exclude:nodemodulesPath
        }
        ]
    },
    plugins:[
        new webpack.optimize.UglifyJsPlugin({
             compress: {
                warnings: false
             }
        }),
        //【2】注意这里  这两个地方市用来配置 common.js 模块单独打包的
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendor",//和上面配置的入口对应
            filename: "vendor.js"//导出的文件的名称
        })
    ]
}

目录结构现在是这样的:


webpack
  |---index.html
  |---webpack-config.js
  |---src
     |---main.js
     |---js
          |---a.js    //a 里面 require 了 common
          |---common.js

执行 webpack 会生成 app.js 和 common.js 两个文件。

多个入口

config 配置:

var config = {    
    entry:{
        m1:path.resolve(__dirname,'src/main.js'),
         m2:path.resolve(__dirname,'src/main1.js')
    },//注意在这里添加文件的入口
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"[name].js"//注意这里使用了 name 变量
    }    
}

webpack-dev-server

在开发的过程中个,我们肯定不希望,每次修改完都手动执行 webpack 命令来调试程序。所以我们可以用 webpack-dev-server 这个模块来取代烦人的执行命令。它会监听文件,在文件修改后,自动编译、刷新浏览器的页面。另外,编译的结果是保存在内存中的,而不是实体的文件,所以是看不到的,因为这样会编译的更快。它就想到与一个轻量的 express 服务器。
安装:


npm install webpack-dev-server --save -dev

config 配置:


var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    //Server Configuration options
    devServer:{
        contentBase: '',  //静态资源的目录 相对路径,相对于当前路径 默认为当前 config 所在的目录
        devtool: 'eval',
        hot: true,        //自动刷新
        inline: true,    
        port: 3005        
    },
    devtool: 'eval',
    output:{
        path:buildPath,
        filename:"app.js"
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),//这个好像也是必须的,虽然我还没搞懂它的作用
        new webpack.NoErrorsPlugin()
    ]
}

我的目录结构:


webpack
  |---index.html
  |---webpack-config.js//我把静态资源目录配置在了这里
  |---src
     |---main.js
     |---js
          |---a.js
          |---common.js

执行命令:


webpack-dev-server --config webpack-dev-config.js  --inline --colors

默认访问地址:

http://localhost:3000/index.html(根据配置会不一样)

有一点需要声明,在 index.html(引用导出结果的 html 文件)里直接引用“app.js”,不要加父级目录,因为此时 app.js 在内存里与 output 配置的目录无关:

<script type="text/javascript" src="app.js"></script>

详细文档在这里查看: http://webpack.github.io/docs/webpack-dev-server.html

如何区分开发及生产环境

在 webpack.config.js 使用 process.env.NODE_ENV 进行判断
在 package.json 里面的 script 设置环境变量,注意 mac 与 windows 的设置方式不一样

"scripts": {
    "publish-mac": "export NODE_ENV=prod&&webpack -p --progress --colors",
    "publish-win":  "set NODE_ENV=prod&&webpack -p --progress --colors",
    "dev-mac": "export NODE_ENV=dev&&webpack-dev-server",
    "dev-win":  "set NODE_ENV=dev&&webpack-dev-server
}

常用 plugins

  • 代码热替换, HotModuleReplacementPlugin
  • 将 css 成生文件,而非内联,ExtractTextPlugin
  • 报错但不退出 webpack 进程,NoErrorsPlugin
  • 代码丑化,UglifyJsPlugin,开发过程中不建议打开
  • 多个 html 共用一个 js 文件(chunk),可用 CommonsChunkPlugin
  • 清理文件夹,Clean
  • 调用模块的别名 ProvidePlugin,例如想在 js 中用 $,如果通过 webpack 加载,需要将 $ 与 jQuery 对应起来

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。