webpack详细项目配置实用教程

webpack是一款打包工具,它是模块化开发的模式、优化了加载速度;
webpack有什么特色?

这些已有的模块化工具并不能很好的完成如下的目标:

  • 将依赖树拆分成按需加载的块
  • 初始化加载的耗时尽量少
  • 各种静态资源都可以视作模块
  • 将第三方库整合成模块的能力
  • 可以自定义打包逻辑的能力
  • 适合大项目,无论是单页还是多页的 Web 应用

一、初始化配置

npm init //npm 初始化 生成 package.json 配置文件

首先是package.json文件,它不是webpack的组成部分,但是常和webpack项目出双入对,先看一下它的大概模样:


1. scripts 命令行脚本通过key:value的方式描述。key是脚本名,value是脚本执行的内容,通过在命令行中输入npm run 脚本名 就可以执行。这一块的内容是实际开发中很实用的,这里不详情展开,参考地址关于这个文件的更多介绍,请移步官方内容 这里我只重点介绍一下以下内个内容:

常见的脚本名有:npm run start , npm run test 。 内置的脚本名(比如start),可以省略run。

2. devDependencies 开发依赖,相应的还有一个dependencies(可以理解为生产环境依赖)

通过npm install 包名 --save-dev (保存到devDependencies),或 --save 保存到(dependencies)

package.json是用来配合包的管理和发布用的,如果你不想发布这个项目,似乎以上内容对项目开发并没有什么好处,但是作为团队协作,它可以方便自己和同事快速搭建项目,管理项目中用到的第三方包。

二、创建webpack配置文件 webpack.config.js

npm install webpack --save-dev //给项目安装webpack 同时创建webpack.config.js文件

module.exports={

  1. 单 入口 与 输出 实例

    entry:'./js/index.js',

    output:{

    path:__dirname,(如果指定路径必须是绝对路径)
//__dirname 代表所有打包的bundle.js的文件位置和入口文件index.js 同一个目录下

path:path.join(_dirname,'dist') (把打包文件打入dist目录下边)

filename:'bundle.js'

}

}

2、多页面配置入口实例 与 输出 实例

var path=require('path');

module.exports={

entry: {

  bundle1: './main1.js', //入口1

  bundle2: './main2.js'//入口2

},

output: {

path:__dirname, (如果指定路径必须是绝对路径)

path:path.join(_dirname,'dist') ,

publicPath:'/dist/' //在对应的html中引入 dist 目录下对应的打包文件

filename: '[name].bundle.js' // [name]是一个变量,会自动替换成entry的key

 }

}

这种用法,对于入口文件需要指定多种类型的文件时比较有用。比如['./main1.js','./main1.css'],
后面用到再细讲。

小结一下:对于entry一共展示了三种形式:

  1. entry:'app.js'  直接写入口文件

  2. entry:{bundle:'./main1.js'} 对象形式

  3. entry:{bundle:['./main1.js']} 对象中的值用数组表示

3、多文件合并一个文件

有两个文件,app.js,cats.js,需要把它们合并成一个bundle.js文件

cats.js:

1

2

var cats = ['dave', 'henry', 'martha'];

module.exports = cats;

app.js:

1

2

cats = require('./cats.js');

console.log(cats);

webpack.config.js :

3

4

5

6

7

8

9

//最简单的webpack配置

module.exports = {

    entry: './app.js', //入口文件地址

    output: {

        filename: 'bundle.js',  //打包后的文件名

    }

};

三、配置常用的loader(加载器)

1)、css loader

npm install css-loader style-loader --save-dev (安装当前项目依赖下)

var path=require('path');

var webpack=require('webpack');

module.exports={

entry: {

  bundle1: './main1.js', //入口1

  bundle2: './main2.js'//入口2

},

output: {

path:__dirname, //(如果指定路径必须是绝对路径)

path:path.join(_dirname,'dist') , 二个path选一个

publicPath:'/dist/' //在对应的html中引入 dist 目录下对应的打包文件

注意:这个publicPath原本是用来配置虚拟目录用的,也就是通过http方式访问时的路径,或者通过webpack HMR方式加载时的输出目录。在这里只能算是一种hack用法。说到output,就要提一下文件缓存[hash]的用法:

1

2

3

4

5

output: {

  path:'./dist',

  publicPath:'./dist/',

  filename: 'bundle_[hash:8].js' //通过:8截取has值的前8位

},

  这个[hash]作用很少被提到,在实际开发中,是很常见的功能,原样输出的hash我觉得太长,可以通过[hash:加数字]的方式进行截取,很方便。

filename: '[name].bundle.js'  // [name]是一个变量,会自动替换成entry的key

 },

plugins:[

new webpack.optimize.uglifyJsPlugin() //对所有打包的文件进行压缩

],

module:{

    loaders:[

        {test:/\.js$/,loader:'babel'},

        {test:/\.css$/,loader:'style!css'} //匹配已 .css 为扩展名的文件

        //test是对该类文件的正则表达式,用来判断采用这个loader的条件,例如 .css 为扩展名的文件

]

}

3.10.0版本

module:{

    rules:[{

        {test:/\.css$/} //匹配已 .css 为扩展名的文件

        use:[

        "style-loader",

        "css-loader"

]

}]

}

}

这里有两个要注意的地方:

  1。 对于有多个加载器串联的情况,webpack,它是从右向左依赖加载的,也就是说先用css-loader,再用style-loader.

  2.  为什么会有一个style-loader, 因为webpack默认是把css文件插在html文件内,通过style标签加载样式的。所以需要用style-loader这个加载器。

如果想要把css用文件的形式link到html中,也是可以的,后面会讲到。

由于我们用了css加载器,所以入口文件其实也可以直接写成:entry:'./app.css'; 效果是一样的。这就体现了,入口文件,不一定要是js格式,只要有对应的加载器,就可以直接在入口中使用,甚至多种类型混合使用,比如['./app.js','app.css'],都是可以的。


webpack 中  css-loader 高阶应用     css作用域 与 css Modules
目的:解决团队开发时类名定义冲突问题

在webpack.config.js 下 css-loader里边配置 modules:true


它的原理是将同样的css 类名 webpack 里边的 hash 把类名替换成唯一的类名 从而避免冲突;


css-loader  高阶应用  自动分离CSS到独立文件

  1. 首先安装
    npm installl  extract-text-webpack-plugin --save-dev  

    2.然后在webpack.config.js 引入extract-text-webpack-plugin 并配置
    
其中filename  的值  name 是参数 css文件定义的 app.js  那么name就是appl
ignoreOrder  参数 代表 是否跳过排序  默认设置为 true

2)、img loader

module:{

    loaders:[

    {test:/\.js$/,loader:'babel'},

    {test:/\.css$/,loader:'style!css'}, //匹配已 .css 为扩展名的文件

    {test:/\.png$/,loader:'file'} , //匹配已 .png为扩展名的文件

    {test:/换成文件夹路径images/,loader:'url'}

/*项目中icon比较多的时候用webpack的‘’url‘’ loader 会把图片路径转化base64 从而减少http请求*/

]

}

3)、Sass loader

当我们用sass编写css样式的时候就可以用到

{test:/\.scss$/,loader:'sass'} ,

四、安装sourcemap调试工具

webpack --devtool source-map 为打包的文件生成 .map 文件

在js文件中写入debugger断点

运行webpack 刷新浏览器 出现debugger断点

在webpack配置文件中安装调试工具

例如如下代码:

module.exports={

    entry:'./js/index.js',

    output:{

    path:__dirname,

    filename:'bundle.js'

},

devtool:'source-map', //便于debugger调试,否则在浏览器的source中看不到自己的代码都是webpack的代码不利于调试

module:{

    loaders:[

    {test:/\.css$/,loader:'style!css'} //匹配已 .css 为扩展名的文件

]

}

}

五、安装babel转换器 (在用JSX、ES6等使用)

npm install babel-loader babel-core babel-preset-es2015 --save-dev

然后创建 .babelrc文件 并写入es-2015的预设

例如如下代码:

{

    "presets":["es-2015"]

}

然后再webpack.config.js中配置一下什么样的文件需要使用babel

module.exports={

    entry:'./js/index.js',

    output:{

        path:__dirname,

        filename:'bundle.js'

},

devtool:'source-map',

module:{

    loaders:[

        {test:/\.js$/,loader:'babel'},

        {test:/\.css$/,loader:'style!css'} //匹配已 .css 为扩展名的文件

]

}

}

六、安装webpack-dev-server 模块热替换功能

  1. npm install webpack-dev-server - -global 先全局安装
  2. npm install webpack-dev-server - -save-dev 在安装到项目依赖中
  3. webpack-dev-server --inline --hot 

注意:默认生成服务器:localhost:8080,可以在devServer中更改。每次改代码保存后,会自动编译并且刷新页面。还可以做到热替换即不刷新页面可以更新。除此之外还有一个proxy功能可以用来配置代理。

    4.WDS 端口号等配置相关(主要还是用在开发环境,生产环境还是用其他的server的软件即可)
在 module.exports 里添加
devServer:{

    host:默认是localhost   也可以写自己的域名
    port:nodejs默认是8080 也可以写80或其他  在window系统可能在命令行前添加 sodu

}

注意:HMR在webpack官方给出了接口用于加载对应模块时 执行的业务逻辑进行局部刷新提高体验度

七、安装webpack插件webpack.optimize.uglifyJsPlugin()对打包的文件进行压缩


在module节点里加入以上 代码 可以 监控文件大小

var path=require('path');

var webpack=require('webpack');

module.exports={

entry: {

  bundle1: './main1.js', //入口1

  bundle2: './main2.js'//入口2

},

output: {

path:__dirname, //(如果指定路径必须是绝对路径)

path:path.join(_dirname,'dist') ,

publicPath:'/dist/' //在对应的html中引入 dist 目录下对应的打包文件

filename: '[name].bundle.js'  // [name]是一个变量,会自动替换成entry的key

 },

devtool:'source-map', //便于debugger调试,否则在浏览器的source中看不到自己的代码都是webpack的代码不利于调试

plugins:[

new webpack.optimize.uglifyJsPlugin() //对所有打包的文件进行压缩

new babili-webpack-plugin();  也可以对文件进行压缩   

],

module:{

loaders:[

{test:/\.js$/,loader:'babel'},

{test:/\.css$/,loader:'style!css'} //匹配已 .css 为扩展名的文件

]

}

}

plugins:的值是一个数组,所有插件都通过npm install进行安装,然后在plugins数组中添加对应的插件配置。有三个插件需要提一下:

1. HtmlwebpackPlugin 这个插件可以把生成的css ,js 插入到html页中的head,body中,这对于加了hash值的输出很有用。这个功能也可以用gulp的insject插件做。不过既然用webpack了,就暂时忘了gulp吧。在具有相似功能的不同的工具之间切换,并不是一个好主意。不过html这款插件有一个小小的问题,它对html中的img不会像css中那样解析。造成dist目录下的html文件,img下的src报错。解决办法是添加html-withimg-loader这个插件。

1

2

3

4

{

     test:/.html$/,

     loader:'html-withimg-loader?min=false'

 },

2. CommonsChunkPlugin 提取公共代码,这个不需要安装,webpack集成有。

1

2

3

4

5

new webpack.optimize.CommonsChunkPlugin({

            name:'vendor',

            filename:'js/vendor.js',

            chunks:['chunk1','chunk2','chunk3']//不写为所有的chunk,

        }),

chunk (块), webpack中另一个非常重要的概念,和entry对应。有三种情况:

2.1  如果entry通过字符串的方式指定的入口文件,那么chunk就是指入口文件,比如entry: './app.js'; 那么可以肯定chunk和'./app.js'一一对应。

2.2 如果是entry:['./app1.js','app2.js']那么chunk就是这两个文件之和。

     *  以上chunk的[name]就是默认的"main".

2.3  如果是下面这种形式:

1

2

3

4

5

entry:{

   index:'./index.js',

   error:'./error.js',

   vendor:['react','redux']

}

那么就会产生多个chunk,[name]分别和index,error,vendor对应。

3. ExtractTextPlugin 这个插件就是开头提到的,从html中分离css的插件。npm install extract-text-webpack-plugin --save-dev

1

2

3

plugins: [

        new ExtractTextPlugin("[name].css"),

]

需要注意的是,如果在[name].css前面加了子路径,如css/[name].css  那么就要小心样式中的图片路径出错,特别是在没有指定publicPah的情况下。background:url(这个地方的图片默认是和chunk的输出路径同级的,如果指定了publicPath,则以publicPath代替,不存在这个问题),但是由于我们人为的指定了打包后的样式放在css/目录下,而图片默认还在原来的目录,这就导致css中引用的图片路径失效。看下面的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

var ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {

  entry: ['./main.js','./icon.css'],

  output: {

    path:'./dist',

    //publicPath:'./dist/',

    filename: 'bundle_[hash:8].js'

  },

  module: {

    loaders:[

        { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'},

        { test: /\.css$/, loader: ExtractTextPlugin.extract('style', 'css') },

    ]

  },

  plugins: [

    new ExtractTextPlugin("css/[name].css"),

  ]

};

从图上看到,添了css子目录之后,样式中的图片,还是原来的路径,而图片并不存在css目录下。

解决办法,要么不加子目录,保持样式文件和图片文件始终在同一层级,要么添加publicPath,相当于使用绝对路径。由于这个是在webpack.config.js中配置的,要更换也很容易。

看起来一切都很美好,可是当我们的html中也用了img标签的时候,问题就来了,还记得html-withimg-loader这个插件吗?它际实上也是调用的url-loader,所以,它最终的图片输出路径也样受publicPath的影响。考虑一下这样的目录结构:

样式文件是位于css子目录,而html则是和图片保持同级的。样式中的图片需要指定为"../",而html中的图片需要指定成"./",这在同一个publicPath中,显示是冲突的。这时就需要权衡一下,要么所有的文件都堆在根目录下,要么html中的图片用别的插件进行处理。总之,不能让这种相冲突的情况发生。

最后再简单说一下webpack.config.js 中的 resolve;

1

2

3

resolve: {

    extensions: ['', '.js', '.vue', '.json']

  },

通常我们都知道通过配置这个属性下的extensions,可以省略扩展名,似乎没有什么可以介绍的,直到有一次我在项目中通过npm install vue --save 安装了vue ,然后我在代码中用import Vue from 'vue' 导入了vue。到这一步都是正常的,可是当我打算进一步使用vue的时候,代码就报错了,然后去查官方文档(出错的时候不要惊慌,大多数情况都会在官方找到解决的办法,比如github中的issue等)。官方介绍如下

“ There are two builds available, the standalone build and the runtime-only build. The difference being that the former includes the template compiler and the latter does not.By default, the NPM package exports the runtime-only build. To use the standalone build, add the following alias to your Webpack config:”

1

2

3

4

5

resolve: {

    alias: {

      'vue$': 'vue/dist/vue.common.js'

    }

  },

大意是说:vue有两种构建方式,独立构建和运行构建。它们的区别在于前者包含模板编译器而后者不包含。而默认 NPM 包导出的是 运行时 构建。为了使用独立构建,要在 webpack 配置中添加下面的别名:添加alias:{'vue$':'vue/dist/vue.common.js'}. 这个别名,同样适用于jquery,zepto这些库。

对于vue来说,如果不用别名,也可以从node_modules/vue/dist/复制vue.common.js到开发目录下,比如./src/vue下面,然后像普通的js文件一样引用, import vue from './src/js/vue.common.js' 这也是可以的。只是和使用别名相比,显的很lower 

八、优化打包速度 noParse

它的值是个数组,每个元素都是一个正则表达式;

也可以在exclude下边添加 include属性 值也是数组里边是正则表达式(正则写需要babel转换的文件,也就是用es6写的js)

   1.  exclude是排除的目录,比如node_modules中的文件,通常都是编译好的js,可以直接加载,因此为了优化打包速度,可以排除。作为优化手 段它不是必须的。

   2. loader: 加载器的名称,每一个加载器都有属于它自己的用法,具体要参考官方说明。

   3. query: 传递给加载器的附加参数或配置信息,有些也可以通过在根目录下生成特殊的文件来单独配置,比如.babelrc

test: /\.js[x]?$/,

        exclude: /node_modules/,

        loader: 'babel-loader',

        query:{

           presets:['react','es2015']

        }

九、ESlint实现代码规范自动化测试    
目的:提高个人代码的质量,提高团队编码风格的统一性,可用性的保障,以及性能优化(先不详细写了)

  1. 首先在项目下安装 npm install eslint --save-dev

    然后在 package.json 文件  scripts中配置eslint
    app/   代表编译app目录下的文件
    webpack.*.js   --cahe  对webpack.*.js相关文件进行缓存

    然后在配置.eslintrc.js  如下图   不懂的配置规则请移步到官网   https://eslint.org/docs/rules/


然后在 命令行中 执行 npm run eslint 就可以对代码进行编辑检测,但是有错误总是手动去改成就会浪费人工时间,这时在1.4 之后的版本 使用 npm run eslint -- --fix 可以自动帮助我们进行修正;
例如 :代码结尾 不加 “分号”  ,字符串用的“双引号“而不是“单引号“  等等问题都会自动修正提高代码质量;
    2:在webpack中配置 eslint
首先 安装 npm install eslint-loader --save-dev 
之后再webpack.config.js中配置 eslint-loader 
module:{

    rules:[

        {                                               

        test:/\.js$/,
        enfore:'pre',
        loader:'eslint-loader',

        options:{

            emitWarning:true

        },

        },

]}

然后在运行之前配置好的 npm run  start会发现跟之前不同的是webpack在编译之前会先对代码进行检测;
另附(根据个人喜好选择):
可以配置在浏览器中显示 检测出来的错误 或者 警告  便于调试
在之前 webpack.config.js 文件中 配置好的devServer中添加配置项 overlay

十、分离项目打包代码和组件代码  (重点)


一、没分离打包时的大小

  1. 如何分离

    然后 npm  run build 对项目进行打包

    会发现多了一个vendor.js 说明已把app.js进行了分离 大小也从175KB 变成 45.1KB

    以上的图 左边是app.js 右边是vendor.js 他们是存在着公共部分代码的 如 A  和 下边节点B C
    所以进行压缩合并配置  如下:
  2. 对公共部分代码进行压缩合并
    在webpack.config.js文件中    如果没导先导 webpack  const webpack=require('webpack');
    然后在plugins  节点下配置 下图标注的部分这个插件是webpack自带的;


    合并完之后app  和 vendor 公共部分进行了合并 如 下图

    然后在进行 npm run build 打包

    会发现上次分离之后打包app文件的45KB 在进行合并打包之后
    变成了 613JB    vendor.js变成46KB       再一次进行了优化
  3. 需要注意的是 分离出来的文件vendor.js 要在html 引入进去并且 放在 bundle.js /app.js上边


十一、使用可视化图表进行统计分析打包过程  (自选)
目的:对后期性能优化做准备,方便找出某些组件之间的依赖关系以及大小,监控编译所占用的时间等等;


然后运行 npm run stats   回生成 stats.json

这里有可视化图表相关内容
http://blog.parryqiu.com/2017/06/16/webpack2-Statistics/

猜你喜欢

转载自my.oschina.net/u/3257418/blog/1617677
今日推荐