关于webpack的使用

关于webpackjavascript

webpakc的是模块打包器.而不是任务执行器。css

它作的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
webpack也提供了便捷的打包流程,项目构建,插件管理等等.
为更好的构建项目,从开发到生产都一一提供了解决方案.
Vue官方也推荐使用的vue-loader也是基于webpack的.html

WebPack和Grunt以及Gulp相比有什么特性

Gulp/Grunt是一种可以优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优势使得Webpack在不少场景下能够替代Gulp/Grunt类的工具。前端

Grunt和Gulp的工做方式是:在一个配置文件中,指明对某些文件进行相似编译,组合,压缩等任务的具体步骤,工具以后能够自动替你完成这些任务。vue

Webpack的工做方式是:把你的项目当作一个总体,经过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的全部依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。java

Webpack的处理速度更快更直接,能打包更多不一样类型的文件。node

一个常见的webpack配置文件react


webpack.config.jswebpack

 

const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');
  const webpack = require('webpack');

  module.exports = {
    entry: {//惟一入口文件路径
      app: './src/index.js'
    },
    output: {
      //publicPath:XXX 能够资金定义路径,build后输出的内容将会放入到这个路径当中
      filename: '[name]-[hash].js', //打包后输出文件的文件名,注意name用方括号括起来,name的值对应的为entry的key值,这样为了区分多个文件 
      path: path.resolve(__dirname, 'dist')//打包后的文件存放的地方(__dirname指向当前执行脚本所在的目录)
    },
    devtool: 'eval-source-map',//Source Maps提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试,强调你只应该开发阶段使用它
    devServer: {//本地开发服务器,浏览器监听你的代码的修改,并自动刷新显示修改后的结果
      contentBase: './dist',//本地服务器所加载的页面所在的目录
      historyApiFallback: true, //不跳转,全部的跳转将指向index.html
      inline: true,//实时刷新
      hot: true
    },
    module: {//Loaders须要单独安装而且须要在webpack.config.js中的modules关键字下进行配置
     rules: [
       {
         test: /\.css$/,//一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
         use: [
             {
                loader: "style-loader"
            }, {
                loader: "css-loader",
                options: {
                    modules: true, //经过CSS模块,全部的类名,动画名默认都只做用于当前模块。 指定启用css modules,把CSS的类名传递到组件的代码中,这样作有效避免了全局污染
                    localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
                }
         ]//css-loader使你可以使用相似@import 和 url(...)的方法实现 require()的功能,style-loader插件使对于CSS文件进行实时渲染到页面中,两者组合在一块儿使你可以把样式表嵌入webpack打包后的JS文件中。
       },
       {
         test: /(\.jsx|\.js)$/,
         use: {
            loader: "babel-loader",//loader的名称(必须)
            options: {//为loaders提供额外的设置选项(可选)
                        presets: [
                            "env", "react"//解析Es6的babel-env-preset包和解析JSX的babel-preset-react包
                        ]
                    }
         },
         exclude: /node_modules/  //include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不须要处理的文件(文件夹)(可选);
        },
        {
         test: /\.css$/,
         use: ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: [{
                loader: "css-loader",
                options: {
                    modules: true,
                    localIdentName: '[name]__[local]--[hash:base64:5]'
                }
            },
            {
                loader: "postcss-loader"//自动添加适应不一样浏览器的css前缀
            }],
         })
        }
       
     ]
    },
    plugins: [
      new CleanWebpackPlugin(['dist']),//清除dist目录
      new HtmlWebpackPlugin({ //依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。
        title: 'Hot Module Replacement'
      }),
      new webpack.NamedModulesPlugin(),//添加该插件更容易观察依赖文件被更新
      new webpack.HotModuleReplacementPlugin(),//动态替换文件,热加载插件
      new webpack.BannerPlugin('版权全部,翻版必究'),//版本申请插件
      new webpack.optimize.CommonsChunkPlugin({
        name: 'common' // Specify the common bundle's name.
      }),
      new webpack.HashedModuleIdsPlugin(),//
      new webpack.optimize.OccurrenceOrderPlugin(),//为组件分配ID,经过这个插件webpack能够分析和优先考虑使用最多的模块,并为它们分配最小的ID
      new webpack.optimize.UglifyJsPlugin(),//压缩JS代码
      new ExtractTextPlugin("style.css")//分离CSS和JS文件
    ],
    
  };

 

 

package.jsones6

{
  "name": "webpack demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack",
    "server": "webpack-dev-server --open",
    "build": "NODE_ENV=production webpack --config ./webpack.prod.js --progress"
  },
  "author": "",
  "license": "ISC","dependencies": {

    "swiper": "^4.0.7",
    "vue": "^2.5.2",
    "vue-router": "^2.8.1",
    "element-ui": "2.2.1",

"react": "^15.6.1",
     "react-dom": "^15.6.1"
  }
}

 

使用webpack

1. 安装

全局安装:

//全局安装
npm install -g webpack

局部安装:

//局部安装
npm install --save-dev webpack

2.工程结构

能够根据项目的实际的状况设置目录。
通常状况下能够设置为源码目录,生产目录。

目录结构以下:

 

3. 写一个webpack.config.js配置文件,首先是入口文件路径(entry)和打包后文件的存放路径(output)。

module.exports = {
  entry:  __dirname + "/src/main.js",//已屡次说起的惟一入口文件
  output: {
    path: __dirname + "/dist",//打包后的文件存放的地方
    filename: "bundle.js"//打包后输出文件的文件名
}

4. 对npm进行配置后能够在命令行中使用简单的npm start命令来执行打包任务。在package.json中对scripts对象进行相关设置便可,package.json中的script会按照必定顺序寻找命令对应位置,具体设置方法以下:

{
  "name": "webpack-sample-project",
  "version": "1.0.0",
  "description": "Sample webpack project",
  "scripts": {
    "start": "webpack" 
  },
  "author": "zhang",
  "license": "ISC",
  "devDependencies": {
    "webpack": "3.10.0"
  }
}

注意:

npm的start命令是一个特殊的脚本名称,其特殊性表如今,在命令行中使用npm start就能够执行其对于的命令。若是对应的此脚本名称不是start,想要在命令行中运行时,须要这样用npm run {script name},npm run build

5. 开发工具

webpack 提供了强大的开发工具

webpack-server 提供了访问页面的服务

webpack-watch 提供了观察文件的变化 

1> source maps

开发老是离不开调试,方便的调试能极大的提升开发效率,不过有时候经过打包后的文件,你是不容易找到出错了的地方,对应的你写的代码的位置的。而webpack能够在打包时为咱们生成source maps,这为咱们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。

webpack的配置文件中配置source maps,须要配置devtool。

对小到中型的项目中,eval-source-map是一个很好的选项,再次强调,你只应该开发阶段使用它。

module.exports = {
  devtool: 'eval-source-map',//source maps,便于调试
  entry:  __dirname + "/src/main.js",
  output: {
    path: __dirname + "/dist",
    filename: "bundle.js"
  }
}

2>使用webpack构建本地服务器

为webpack打包生成的文件提供web服务,让你的浏览器监听你的代码的修改,并自动刷新显示修改后的结果,其实Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js构建,能够实现你想要的这些功能,不过它是一个单独的组件,在webpack中进行配置以前须要单独安装它做为项目依赖。

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

webpack.config.js配置文件以下:

module.exports = {
  devtool: 'eval-source-map',

  entry:  __dirname + "/src/main.js",
  output: {
    path: __dirname + "/dist",
    filename: "bundle.js"
  },

  devServer: {
    contentBase: "./dist",//设置本地服务器访问的基本目录
    historyApiFallback: true,//不跳转
    inline: true//实时刷新
  } 
}

package.json中的scripts对象中添加以下命令,用以开启本地服务器:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack",
    "server": "webpack-dev-server --open"
  },

在终端中输入npm run server,便可在本地的8080端口查看结果

6. Loaders

Loaderswebpack提供的最激动人心的功能之一。经过使用不一样的 loaderwebpack有能力调用外部的脚本或工具,实现对不一样格式的文件的处理,好比说分析转换scss为css,或者把下一代的JS文件(ES6,ES7)转换为现代浏览器兼容的JS文件,对React的开发而言,合适的Loaders能够把React的中用到的JSX文件转换为JS文件。
 
Loaders须要单独安装而且须要在webpack.config.js中的modules关键字下进行配置。
 
Loaders的配置包括如下几方面:
  • test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
  • use: 进行转换时,应该使用哪一个loader
  • loader:loader的名称(必须)
  • include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不须要处理的文件(文件夹)(可选);
  • query:为loaders提供额外的设置选项(可选)
1> css
webpack提供两个工具处理样式表, css-loader和  style-loader,两者处理的任务不一样。
css-loader使你可以使用相似 @import和  url(...)的方法实现  require()的功能;
style-loader将全部的计算后的样式加入页面中;
两者组合在一块儿使你可以把样式表嵌入webpack打包后的JS文件中。

安装style-oader、css-loader,loader的做用就是将文件进行处理(编译,压缩)

npm install --save-dev style-loader css-loader
module.exports =     
{
    module: {
      rules: [
        {
          test: /\.css$/, //指定匹配文件,使用style-loader,css-loader
          use: [
            'style-loader',
            'css-loader'
          ]//引入的顺序相当重要,不可改变
      }]
     }
}

css预处理器

Sass 和 Less 之类的预处理器是对原生CSS的拓展,它们容许你使用相似于variablesnestingmixinsinheritance等不存在于CSS中的特性来写CSS,CSS预处理器能够这些特殊类型的语句转化为浏览器可识别的CSS语句。

如下是经常使用的CSS 处理loaders:

  • Less Loader
  • Sass Loader
  • Stylus Loader

-PostCSS

使用PostCSS来为CSS代码自动添加适应不一样浏览器的CSS前缀。

首先安装postcss-loader 和 autoprefixer(自动添加前缀的插件)

npm install --save-dev postcss-loader autoprefixer

在webpack配置文件中添加postcss-loader,在根目录新建postcss.config.js。

//webpack.config.js
module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    }
}

postcss.config.js

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

2> babel

Babel实际上是一个编译JavaScript的平台,它能够编译代码帮你达到如下目的:

  • 让你能使用最新的JavaScript代码(ES6,ES7...),而不用管新标准是否被当前使用的浏览器彻底支持;
  • 让你能使用基于JavaScript进行了拓展的语言,好比React的JSX;

babel转化语法所需依赖项:

babel-loader: 负责es6语法转化

babel-core: babel核心包

babel-preset-env: 告诉babel使用哪一种转码规则进行文件处理

 

先来一次性安装依赖包 

// npm一次性安装多个依赖模块,模块之间用空格隔开
npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react

webpack中配置Babel的方法以下:

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: [
                            "env", "react"
                        ]
                    }
                },
                exclude: /node_modules/
            }
        ]
    }
};
Babel其实能够彻底在  webpack.config.js中进行配置,可是考虑到babel具备很是多的配置选项,在单一的 webpack.config.js文件中进行配置每每使得这个文件显得太复杂,所以一些开发者支持把babel的配置选项放在一个单独的名为 ".babelrc" 的配置文件中。咱们如今的babel的配置并不算复杂,不过以后咱们会再加一些东西,所以如今咱们就提取出相关部分,分两个配置文件进行配置(webpack会自动调用 .babelrc里的babel配置选项),以下:
 
webpack.config.js
module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: "babel-loader",
                exclude: /node_modules/
            }
        ]
}

.babelrc

{
  "presets": ["@babel/preset-env"]
}

 

3> Vue-Loader

.vue 文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每一个 .vue 文件包含三种类型的顶级语言块 <template><script> 和 <style>,还容许添加可选的自定义块:

<template>
  <div class="example">{{ msg }}</div>
</template>

<script>
export default {
  data () {
    return {
      msg: 'Hello world!'
    }
  }
}
</script>

<style>
.example {
  color: red;
}
</style>

<custom1>
  This could be e.g. documentation for the component.
</custom1>

vue-loader 会解析文件,提取每一个语言块,若有必要会经过其它 loader 处理,最后将他们组装成一个 CommonJS 模块,module.exports 出一个 Vue.js 组件对象。

vue-loader 支持使用非默认语言,好比 CSS 预处理器,预编译的 HTML 模版语言,经过设置语言块的 lang 属性。例如,你能够像下面这样使用 Sass 语法编写样式:

<style lang="sass">
  /* write Sass! */
</style>

 

7. 插件(Plugins)

插件(Plugins)用来拓展webpack功能,他们会在整个构建过程当中生效,执行相关的任务。

loaders是在打包构建过程当中用来处理源文件的(JSX,Scss, Less),一次处理一个。

plugins并不直接操做单个文件,是对整个构建过程起做用。

 

使用插件的方法:

使用某个插件,须要在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数组)。

例如:添加了一个给打包后代码添加版本声明的插件

const webpack = require('webpack');

module.exports = {
...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('版权全部,翻版必究')
    ],
};

 

下面推荐几个经常使用的插件:

HtmlWebpackPlugin

依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。这在每次生成的js文件名称不一样时很是有用(好比添加了hash值)。

安装:

npm install --save-dev html-webpack-plugin

webpack.config.js:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    ...
    plugins: [
        new webpack.BannerPlugin('版权全部,翻版必究'),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"//new 一个这个插件的实例,并传入相关的参数
        })
    ],
};

CleanWebpackPlugin

清除目录的插件。

添加了hash以后,会致使改变文件内容后从新打包时,文件名不一样而内容愈来愈多,所以这里介绍另一个很好用的插件clean-webpack-plugin

引入clean-webpack-plugin插件后在配置文件的plugins中作相应配置便可:

 

安装:

npm install clean-webpack-plugin --save-dev 

webpack.config.js:

整个配置文件,注意插件的配置顺序.

  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    ...
    plugins: [
      new CleanWebpackPlugin(['dist']),//清除dist目录
      new HtmlWebpackPlugin({ //生成一个html页面指定其title,而后会自动将js文件生成引入js代码
        title: 'Output Management'
      })
    ]
  };

 

Hot Module Replacement (HMR)

主要是启动服务后文件能够进行热更新,例如css样式或者js等文件变动,会自动更新到页面上.只能用于开发环境不能用于生产环境.

它容许你在修改组件代码后,自动刷新实时预览修改后的效果。

在webpack中实现HMR也很简单,只须要作两项配置

  1. 在webpack配置文件中添加HMR插件;
  2. 在Webpack Dev Server中添加“hot”参数;

webpack.config.js

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin'); module.exports
= { ... devtool: 'eval-source-map', devServer: { contentBase: "./public",//本地服务器所加载的页面所在的目录 historyApiFallback: true,//不跳转 inline: true, hot: true }, ... plugins: [ new webpack.BannerPlugin('版权全部,翻版必究'), new CleanWebpackPlugin(['dist']), new HtmlWebpackPlugin({ template: __dirname + "/app/index.tmpl.html"//new 一个这个插件的实例,并传入相关的参数 }), new webpack.NamedModulesPlugin(),//添加该插件更容易观察依赖文件被更新 new webpack.HotModuleReplacementPlugin()//热加载插件 ], };

目前为止,咱们已经使用webpack构建了一个完整的开发环境。

产品阶段的构建

在产品阶段,可能还须要对打包的文件进行额外的处理,好比说优化,压缩,缓存以及分离CSS和JS。

对于复杂的项目来讲,须要复杂的配置,这时候分解配置文件为多个小的文件可使得事情层次分明。所以最好添加以下配置到配置文件的入口.

process.env.NODE_ENV = 'production'

webpack 配置能够提炼出来,使用webpack-merge将webpack的配置文件进行合并。

咱们能够建一个webpack.common.js文件,而后建立一个webpack.prod.js,webpack.dev.js,那么能够将prod,dev引入common共同引用参数.

common文件

const path = require('path');
 const CleanWebpackPlugin = require('clean-webpack-plugin');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   entry: {
     app: './src/index.js'
   },
   plugins: [
     new CleanWebpackPlugin(['dist']),
     new HtmlWebpackPlugin({
       title: 'Production'
     })
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist')
   }
 };

生产环境:

webpack提供了一些在发布阶段很是有用的优化插件,它们大多来自于webpack社区,能够经过npm安装,经过如下插件能够完成产品发布阶段所需的功能

  • OccurenceOrderPlugin:为组件分配ID,经过这个插件webpack能够分析和优先考虑使用最多的模块,并为它们分配最小的ID
  • UglifyJsPlugin:压缩JS代码;
  • ExtractTextPlugin:分离CSS和JS文件(将css引入到js文件中,会一块儿打包成js文件)

OccurenceOrder 和 UglifyJS plugins 都是内置插件,你须要作的只是安装其它非内置插件

npm install --save-dev extract-text-webpack-plugin

webpack.prod.js

 const merge = require('webpack-merge');
 const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
 const HtmlWebpackPlugin = require('html-webpack-plugin');
 const ExtractTextPlugin = require('extract-text-webpack-plugin');
 const common = require('./webpack.common.js');

 module.exports = merge(common, {
   module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
   plugins: [
     new webpack.BannerPlugin('版权全部,翻版必究'),
     new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html"
     }),
     new webpack.optimize.OccurrenceOrderPlugin(),
     new webpack.optimize.UglifyJsPlugin(),
     new ExtractTextPlugin("style.css")
   ]
 });

开发环境:

const merge = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  devtool: 'inline-source-map',
   devServer: {
     contentBase: './dist'
   }
 });

 

 8. 代码管理

默认的状况下,webpack会把引用的文件都会build到单独的文件当中.咱们可能会把一些第三方的模块放到一个单独文件里.

须要对配置文件作以下改动:

     //plugins数组当中添加一下参数
     new webpack.optimize.CommonsChunkPlugin({
       name: 'common' // Specify the common bundle's name.
     })

9. 垫片

当咱们须要全局引入一个变量,咱们可使用ProvidePlugin。(webpack不推荐这样作,由于会影响到模块化编程)

每一个js文件就不须要去import引入对应的代码

plugins: [
      new webpack.ProvidePlugin({
       _: 'lodash'
      })
]

或许只须要部分第三方库的功能,咱们能够这样进行配置

plugins: [
      new webpack.ProvidePlugin({
       _: 'lodash',
       join:['lodash', 'join']//咱们能够这样进行配置 ['module', 'child', 'child']
      })
]

10. 缓存

缓存无处不在,使用缓存的最好方法是保证你的文件名和文件内容是匹配的(内容改变,名称相应改变)

webpack能够把一个哈希值添加到打包的文件名中,使用方法以下,添加特殊的字符串混合体([name], [id] and [hash])到输出文件名前。

module.exports = {
..
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: "bundle-[hash].js"
    },
   ...
};

还有个问题webpack默认的hash是根据module.id以及内容生成,而module.id根据解析文件的顺序生成,一个重要的问题是每次改动引入的文件,就可能会形成其它文件hahs不一致.

这时候就须要HashedModuleIdsPlugin插件,指定使用Path以及内容做为hash的内容.

只须要配置文件当中在plugins增长以下配置:

plugins:[
    ...,
    new webpack.HashedModuleIdsPlugin(),
    ...
]


 本文根据https://www.jianshu.com/p/42e11515c10f改写,加了一些本身的理解,但愿对你们有帮助。

相关文章
相关标签/搜索