webpack2.0 基本使用

webpack2.0 基本使用

  webpack是一款前端模块打包工具。这里有两个概念:模块,打包。现代web开发越来越复杂,把所有的js代码都写到一个文件中,导致后期维护很困难,所以提出了模块化的概念,代码进行拆分,写成一个个小的模块。但是js 设计当初并没有为这种开发模式提供支持,后面出现了commanjs ,amd, ES6 的模块化方案, 但浏览器并不能直接支持,所以要把模块化的代码进行转换,转换成浏览器能识别的内容。这就是打包吧,把多个文件打包成一个浏览器支持的文件,webpack 就是做这个工作的,当然它也不限于做这个工作,复杂的功能后面再说。现在先学习一下怎么打包吧。

  1, 新建webpack文件夹并进入,打开cmd 命令窗口,输入npm init –y,快速创建一个package.json 文件。再新建src和dist文件夹,index.html,src目录存放源代码,dist 目录存放打包后的代码. 在src 下新建index.js, mes.js. 简单项目结构如下:

webpack2.0 基本使用

  index.js,mes.js 就是两个不同的模块, 简单来说,一个js 文件就是一个模块。现在ES6 对模块化进了标准化,我们就采用ES6 的模块化方案,在一个模块中引入另外一个模块用import , 一个模块要暴露一个功能给另外一个模块用export. 我们来写一个简单的功能,mes.js暴露一个字符串hello World 出去,index.js 中引入获取hello world, 并显示到页面上。代码如下:

  mes.js

  export let mes = "Hello world"  // 暴露mes变量出去

  index.js

import {mes} from './mes';  // 引入mes模块中的mes变量。
document.body.innerHTML = mes;

  前面已经说了,index.js 不能直接使用,因为浏览器并不支持es6 的module模块。如果我们在index.html 中直接用script 标签引入index.js,浏览器就会报错。 这时就用到了webpack对这两个js 文件进行打包,打包成一个浏览器可以识别的文件,供我们在浏览器中使用。

2,  使用webpack进行打包, 就要先安装webpack。webpack 的安装方式有两种:全局安装 和 本地安装。

  全局安装:在当前文件夹中调用cmd 命令窗口,输入 npm install webpack –g, 等待安装完成,

webpack2.0 基本使用

  安装完成后,就可以命令行中使用webpack 命令,命令行中输入 webpack src/index.js  dist/build.js ,它表示,对src中的index.js文件进行打包,输出到dist目录下的build.js 中。

webpack2.0 基本使用

  打包完成后,可以看到dist目录下多了一个build.js文件,把这个文件引入到index.html文件中,

webpack2.0 基本使用

  在本地打开index.html 可以看到Hello world 字样,表示打包成功。

  本地安装:在当前目录的cmd 命令窗口中输入 npm install webpack --save-dev , 但这样我们无法在命令行中使用webpack 了,当我然我们要先卸载全局安装的webpack,

  卸载全局安装的webpack,用的命令是npm uninstall webpack -g 

webpack2.0 基本使用

  卸载完成后,本地安装webpack, 输入npm install webpack --save-dev , 安装完成后, 输入webpack,报错了,没有这个指令。

webpack2.0 基本使用

   但这时webpack 文件夹中多了一个node_modules文件夹,表示安装到了本地。在node 中,把任何东西安装到本地,它们都会安装到node_modules中,安装到本地的命令怎么用,

npm script 命令。打开package.json 文件,找到scripts 字段,写入 "build": "webpack src/index.js dist/build.js" 

webpack2.0 基本使用

  这样在命令行中输入npm run build也可以启用webpack 进行打包。

webpack2.0 基本使用

  dist目录下还是会有build.js 文件,用浏览器打开index.html, 还是可以看到Hello world, 证明打包成功。 

  两种安装方式,到底该用哪一种,推荐本地安装。全局安装有一个版本管理问题, 如果我们的项目中,有的用webpack 1.0,有的用webpack2.0 ,而全局webpack 却只有一个命令,那就不好办了。本地安装却没有这个问题。If you are using npm scripts in your project, npm will try to look for webpack installation in your local modules for which this installation technique is useful. 当我们使用npm scripts 时,npm 会寻找本地安装的webpack ,这就解决版本问题, 每一个项目下都使用本地安装webpack , 互不影响。

  3,webpack 配置文件(webpack.config.js)

  我们进行了简单的打包操作,但是要想使用更强大的打包功能,就需要使用webpack的配置文件 webpack.config.js. 先了解一下配置文件中的两个概念:entry, output

  •   entry 入口文件:webpack以哪个文件作为项目的入口, 就是webpack 打包的时候的从哪个文件开始。 相当于webpack 命令中 src/index.js 
  •   output: webpack 打包完成后的文件放到什么地方。相当于webpack 命令中 dist/build.js 

  现在用webpack.config.js来完成上面的打包工作. 在webpack文件夹下,新建一个js文件,命名为webpack.config.js. 内容如下: 

webpack2.0 基本使用
  var path = require('path');    // 引入path模块

  module.exports = {
    entry: path.join(__dirname,'src/index.js'),  // 指定入口文件,
    output:{
      path:path.join(__dirname,'dist'),        // 打包到哪个路径下,
      filename:'build.js'             // 打包成功后的文件名称
    }
  }
webpack2.0 基本使用

  webpack2.0 基本使用

 

  webpack2 建议我们使用 绝对路径,所以引入nodeJs 的path模块,主要用到了path.join方法, 它接受路径参数,然后合并成一个完整的路径。

  这时npm scripts 中的 "build": "webpack src/index.js dist/build.js"  改成 "build": "webpack".  

 webpack2.0 基本使用

  这时在命令行中执行npm run build,同样可以完成打包。

  三种打包方式,我们生成了三次build.js 文件,我们也不知道是哪一次生成哪一个文件,所以最好把以前生成的文件删除,保证每次打包完,都是最新的文件。当然,我们也不用每次都手动删除,我们可以使用rimraf 模块。rimraf 就是用来删除文件或文件夹. 首先要安装它, cnpm i rimraf --save-dev,  rimraf 安装到本地后,需要npm script 命令, “rimraf dist” 就可以删除 dist 目录. 修改“build”: “rimraf dist && webpack”  && 把两个命令连接起来,执行完前面的再执行后面的,依次从左向右执行, 这样我们每次执行build 命令都会先删除,再重新生成。

  最后,再说一点,有时还会看到 “webpack --config mywebpack.config.js”。 --config 指定我们打包要使用的配置文件。因为使用webpack 命令时,它会自动寻找项目中的配置 文件,如果项目中有一个配置文件,这没有问题,但是如果项目中有许多配置文件,它只会使用它最先找到的一个,这就不是我们想要的了,所有我们要进行配置 使用到了—config 参数。如果我们只用一个webpack.config.js 文件, scripts 里面可以直接写 “build”: “webpack”; 如果有多个文件,就要指定我们想要使用哪个配置文件进行打包webpack --config mywebpack.config.js

  4,webpack-dev-server 热更新和热替换。

   上面的打包方式,在项目开发中会遇到一个问题,就是每次修改代码后,如修改index.js文件的内容后,我们都要在命令行中输入npm run build, 然后等待打包完成,打包完成后,还要重新刷新浏览器才能看到效果。这非常麻烦,怎么解决这个问题,这要用到了webpack-dev-server.

  webpack-dev-server 是 webpack自带的一个小型服务器,当我们用服务器的方式访问html页面,每当有文件改动时,浏览器会自动刷新页面来反映我们做出的更改,这也就是所谓的liveload 或hotload. 首先 npm install webpack-dev-server --save-dev 安装它,

webpack2.0 基本使用

  然后在npm script 命令新建一个命令,"dev": "webpack-dev-server" 

webpack2.0 基本使用

  这时,在命令行中输入npm run dev 启动服务器,在浏览器地址栏器输入localhost:8080, 页央显示hello World, 但是当我们改变mes.js中的Hello World 为Hello时,浏览器的内容并没有发生变化,和我们预想的不一样。这是 怎么回事? 原来是因为执行过npm run build 命令,dist文件夹中有build.js 文件,我们的html 文件是引用这个文件,把dist 目录删除,然后浏览器刷新,什么都没有,打开控制台,可以看到报错了,找不到build.js文件。

webpack2.0 基本使用

  我们要知道,启动webpack-dev-server 时,它也会进行打包,只不过它是把打包成功后的文件放到内存中,而不是放到硬盘中,那它放到内存的什么地方呢? 我们必须知道打包后的build.js 放到什么地方,因为我们的html 文件中要进行引入,script 标签中src就是指向build.js文件地址。 我们再看一个启动webpack-dev-server  时发生了什么? 当输入npm run dev 时,我们看到

webpack2.0 基本使用

  

  Project is running at http://localhost:8080/ 整个项目运行在localhost:8080下。这也就是我们在浏览器中输入localhost:8080的原因。

  webpack output is served from /: 通过这一句我们才知道,webpack-dev-server  默认把打包后的文件放到了根目录下,在服务器中,/ 表示的就是根目录。那我们在 src 引入路径的时候,就知道了,src= ‘bulid.js’ 就可以了。修改index.html 中 script 的src 为 src="build.js", 修改之后,浏览器刷新,可以看到hello World, 这时再更改mes.js中的 hello World 为 hello ,浏览器自动刷新,显示hello,成功了。

  但这里有一个问题,当执行npm run build 时,dist 目录下会生成一个build.js, 本地打开index.html 又要引入这个文件,需要对html 中的js 路径进行修改为src="dist /build.js", 这样两种状况下要来回切换, 不利于开发,这两种不同的状态,可以理解为, 一个是开发环境,一个是生产环境.  dev 状态下是开发环境, build  是生产环境. 有没有办法让它们统一起来? 有,那就是output 中另外一个重要的配置 publicPath, 既然我们的生产环境是用 dist/build.js, 我们可不可以把让webpack-dev-server 打包时也放到dist 目录, publicPath 配置成 'dist/' 就可以了。

webpack2.0 基本使用

  只要保证output 中的publicPath 和path 路径一致,就可以了。

  还有一个热更新HRM,  当文件内容发生变化时,不用刷新整个页面,只是把变化的部分替换掉。当然它的配置有点小麻烦,不过就是按步骤就可以了。

  首先,它利用webpack-dev-server和 webpack.config.js 配置文件生成一个服务器,在webpack文件夹下新建一个dev-server.js 文件。

  

5, 使用webpack 配置文件

  webpack 把所有的资源都当做模块,对模块的解析都要用到loader(模块加载器)。 现在的src index.js 中写es6 语法,让webpack 转化成es5 的语法,体验一下loader 的使用。es6+ 转化成es5 要用到babel loader。

  npm install babel-loader babel-core babel-preset-es2015 --save-dev 安装babel-loader, 更新 webpack.config.js 文件

webpack2.0 基本使用
module.exports = {
    entry: "./src/js/index.js",
    output: {
        path:"./build/js",
        filename: "index.js"
    },
    module: {
        rules:[
            {
                test: /\.js$/,
                loader:"babel-loader",
                include: /src/,
                exclude: /node_modules/
            }

        ]
    }
}
webpack2.0 基本使用

  1, output: 定义打包后的文件放到什么地方。有两个参数:path: 打包后的文件放在哪里,是一个路径,filename,:打包后的文件的名字。

  2, module: 定义打包规则,webpack2 用的是rules 来指定规则,它是一个数组,里面是每一个对象,对不同的文件指定具体的规则。

    test:它是一个正则表达式,表示对哪种类型文件应用这个loader。loader: 指定具体的loaders, 注意,webpack2 中 babel-loader 后面的 -loader 字符最好不要省略。include: 是 一个文件夹,它表示只对src 目录下的js文件进行转换,exclude 就是忽略这个文件夹目录。

  3, webpack2 直接支持 es6 中的module模式,就是 import 和export 来引入或输出模块,webpack tree shaking 正是利用 es6 的module 模式来完成的。但当我们用babel 对js 进行编译的时候,它会把它转换成commonJS格式,所以需要对babel 时进行规定。.babelrc 是对babel 进行配置,下面的module: false 就是不要转换成commanJs 格式。

{
    presets: [
        ["es2015", {"module":false}]
    ]
}

  再来体验 多个loader 对一个文件进行解析。平常写css 都是用sass, 那就需要把sass 转换成css. 这时需要安装sass-loader, css-loader, style-loader.   npm install sass-loader node-sass css-loader  style-loader --save-dev

  css-loader 处理的是css文件中的url import 等等, style-loader 是把样式插入html 文件中style 标签中,内嵌样式。配置文件为

webpack2.0 基本使用
module.exports = {
    entry: "./src/js/index.js",
    output: {
        path:"./build/js",
        filename: "index.js"
    },
    module: {
        rules:[
            {
                test: /\.js$/,
                loader:"babel-loader",
                include: "/src/",
                exclude: "/node_modules/"
            },
            {
                test: /\.scss$/,
                use: ["style-loader", "css-loader", "sass-loader"],
            }

        ]
    }
}
webpack2.0 基本使用

  可以看到,当用多个loader 去处理 一个文件时,它用的是use 来指定规则. 用它的处理顺序就从右向左, 先使用sass-loader, 把sass 文件转换成 css 文件,所以sass 放在最右边,然后把转换好的css 文件中的url 进行处理,css 放到sass 的左边, 最后把css 样式放入到html 元素中,那就是style-loader, 它放到最左边。

  当然 还有一个常用的 loader 进行url-loader, 处理图片,文字等等, 比如把图片变成转成base64编码的, 这样就可以减少http请求数量。当然也不是所有图片都要转化成base 64 一般都是小于10kb 的图片进行转换,否则,会增大css 文件的大小。这需要options 对这个loader 进行配置。

webpack2.0 基本使用
 {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
      name: "img/[name].[hash:7].[ext]"
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000
        }
      }
webpack2.0 基本使用

   4, 插件

  webpack 自带了一些插件,如js 压缩插件 UglifyJsPlugin。每一个插件的使用是通过构造函数生成一个对象, 当然,构造函数可以接受一个对象参数,对这个插件进行配置。所有的插件,都放到plugins  属性下,它是一个数组,每一个插件都是数组的一项。使用插件的时候,需要依赖webpack, 所以我们的配置文件中还要引入webpack. 再在这里补充一下吧, webpack2推荐使用绝对路径,所以 output中的path 要使用绝对路径,这就要用到node 的path 模块

webpack2.0 基本使用
var path =  require("path");
var webpack = require("webpack");
module.exports = {
    entry: "./src/js/index.js", 
  output: { 
    path: path.join(__dirname, "build"), 
    filename: "index.js" 
  }, 
  plugins: [ 
    new webpack.optimize.UglifyJsPlugin() 
  ] 
}
webpack2.0 基本使用

  当然,还有第三方插件可以使用,如 webpack-html-plugin 插件, 它在output中指定的path目录下,自动生成html 文件,且自动插入通过webpack 生成的js文件。

plugins: [
    new HtmlwebpackPlugin({
      title: "hello World"
    })
  ]