首页 > 技术文章 > vue中webpack相关的配置

qianzhengkai 2020-06-03 00:10 原文

webpack

什么是webpack?

  • 官方解释:

    • At its core,webpack is a static moudle bundler for modern JavaScript applications
    • 从本质上来讲,webpack 是一个现代化的JavaScript应用的静态模块打包工具。
  • 但是他到底是什么呢?(两个关键字)

    • 模块
    • 打包
  • 前段模块化:

    • 在前面学习中,我们已经用了大量的篇幅解释为什么前段需要模块化
    • 而且我也提到了目前使用前段模块化的一些方案:AMD,CMD,CommonJS,ES6
    • 在ES6之前,我们要想进行模块发开发,就必须借助于其他工具,让我们可以进行模块化开发
    • 并且在通过某快画开发完成了项目后,还需要处理模块间的各种依赖,并且将其进行整合打包
    • 而 webpack其中一个核心就是让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖关系
    • 而且不仅仅是JS文件,我们的CSS,图片,json文件等等webpack中都可以被当做某块来使用
    • 这就是webpack模块化的概念。
  • 如何理解打包的概念

    • 就是webpack中的各种资源模块进行打包合并成一个或多个(Bundle)
    • 并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript 转成JavaScript等等操作
    • 但是打包的操作似乎grunt、gulp 也可以帮助到我们,那么有什么不同呢
  • 和grunt/gulp的对比

    • grunt/gulp 的核心是Task
    • 我们可以配置一系列的task,并且定义task要处理的事务(例如ES6,ts转化,图片压缩,scss转成css)
    • 之后让grunt/gulp 来一次执行这些task,而且让整个流程自动化
    • 所以grunt/gulp也被成为掐断自动化管理工具
  • 什么时候使用grunt/gulp?

    • 如果你的工程模块非常简单,甚至是没有用到模块化的概念
    • 只需要进行简单的合并、压缩,就使用grunt/gulp即可
    • 但是如果整个项目使用了模块化管理,而且相互依赖非常强,则选择webpack更优
  • 所以,grunt/gulp 和webpack 有什么不同呢?

    • grunt/gulp 更强调的是前段流程的自动化,模块不是他的核心
    • webpack 更加强调模块化开发管理,而文件压缩合并,预处理等功能,是他附带的功能。

webpack安装

  • webpack是模块化的打包工具
  • 我们使用模块化开发,无法给用户直接使用,需要通过webpack打包。
  • webpack为了可以正常运行,必须依赖node环境。
  • node环境为了可以正常执行很多代码,必须依赖其中很多的包
  • npm 就是管理这些node依赖包的工具(node packages manager)
  • 所以安装webpack之前首先需要安装Node.js ,Node.js 自带了软件包管理工具npm
  • 查看node版本:node -v
  • 使用npm安装webpack:
# 安装webpack
# @ 后面加版本号
# -g 指的是全局安装
npm install webpack@3.6.0 -g
  • 简单的打包命令
# 利用webpack将 main.js 打包成 dist文件夹下的bundle.js
# webpack 会帮你处理各个模块间的依赖
webpack ./src/main.js ./dist/bundle.js

我们正常一个vue项目会有 一个src文件和一个dist文件夹

  • src文件夹:用于存放项目源码
  • dist文件夹:用于存放打包后的文件(distribution(发布))

本地安装(局部安装)webpack

# --save-dev  开发时依赖  webpack一旦打包好就不需要了,所以属于开发时的依赖
npm install webpack@3.6.0 --save-dev

package.json 中定义启动

  • 但是每次执行都需要敲一长串的命令,并不是很方便

    • 我们其实可以在package.json 的script 中定义自己的执行脚本
  • Package,json 中的script 的脚本在示性式,会按照一定顺序寻找对应的命令

    • 首先,会虚招本地的node_modules/.bin 路径中对应的命令
    • 如果没找到,会去全局的环境变量中寻找
  • 如何执行我们的buld 指令:

npm run build

Package.json 配置信息

{
  "name": "meetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.6.0"
  }
}

什么是loader?

上链接:https://www.webpackjs.com/loaders/

  • loader 是webpack非常核心的一个概念
  • webpack用来做什么呢?
    • 在我们之前的实例中,我们主要是用webpack来处理我们写的js代码,并且wbpack会自动处理js之间的依赖
    • 但是,在开发中我们不仅仅有几本的极速代码处理,我们也需要加载css,图片,也包括一些高级的将ES6转ES5的代码,将TypeScript 转成ES5 代码,将scss ,less 转成css, 将.jsx .vue 转成js文件等
    • 对于webpack本身的能力来说这是不支持的
    • 但是,webpack 扩展对应的loader 就可以了
  • loader的使用过程:
    • 1,通过npm安装需要使用的loader
    • 2,在webpack.config.js中的moudules关键字下面进行配置
  • 大部分loader我们都可以在webpack官网中找到,并且学习对应的方法

less文件处理-准备工作

  • 如果我们希望在项目中使用less,scss,stylus来写样式,webpack是否可以帮助我们处理呢?
  • 我们以less为例,其他都一样。
  • 我们还是先创建一个less文件,依然放在css文件夹中

ES6语法处理

  • 如果仔细阅读webpack中打包的js文件,发现写的ES6语法并没有转成ES5,name就以为这可能一些对ES6还不支持的浏览器没有办法很好的运行我们的代码
  • 在前面我们说过,如果希望将ES6的语法转成ES5的,那么久需要babel
npm install --save-dev babel-loader babel-core babel-preset-es2015
  • 配置webpack.config.js 文件
module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['es2015']
        }
      }
    }
  ]
}

// 或者你可以使用options属性来给loader传递参数
module: {
  rules: [
    {
      test: /\.js$/,
      // exclude 排除 下面文件夹中的文件不需要传唤
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: [require('@babel/plugin-transform-object-rest-spread')]
        }
      }
    }
  ]
}

vue发布的版本问题:

  • runtime-only —> 代码中,不可以有任何template
  • runtime-complier —> 代码中,可以有template ,因为有 complier 可以用于编译template

注意:通过 npm install vue —save 直接安装vue 后,在 项目中使用vue ,然后通过webpack打包后运行会报错。

  • 修改完成后,重新打包,运行程序:
    • 打包过程中没有任何问题(因为只是多打包了一个vue的js文件而已)
    • 但是运行程序,没有出现你想要的下过,而且浏览器中报错
  • 这个错误说的是我们使用的是runtime-only 版本的vue。
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

(found in <Root>)

解决办法:

上链接:

// package.json
{
  "name": "meetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.6.0"
  },
  "dependencies": {
    "vue": "^2.6.11"
  }
}

// wepack.config.js

// 这个文件是配置webpack的入口和出口文件


// node.js 语法获取绝对路径
// 1. 导入path模块,聪node包中找的
const path = require('path');

module.exports = {
  entry:'./src/main.js',
  output:{
    path:path.resolve(__dirname,'dist'),  // 必须是绝对路径,这里是通过node.js 的path 实现的路径的拼接
    filename:'bundle.js'  // bundle 打包
  },
  // vue 配置这个可以使用template
  resolve:{
    // alias: 别名
    alias:{
      // 当我们 导入 from vue 的时候,指向执行的路径去找文件  vue.esm.js 中包含 complier
      'vue$':'vue/dist/vue.esm.js'
    }
  }
};

认识plugin(插件)

  • 什么是plugin?
    • plugin是插件的意思,通常是用于对某个现有的架构进行扩展
    • webpack中的插件,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等
  • loader 和 plugin区别
    • loader 朱勇用于转换某些类型的模块,它是一个转换器
    • plugin是插件,它是对webpack本身的扩展,是一个扩展器
  • plugin的使用过程:
    • 步骤一:通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
    • 步骤二:在webpack.config.js中的plugins中配置插件
  • 下面我们通过示例来看看可以通过哪些插件对现有的webpack打包过程进行扩容,让我们webpack变得更加好用

插件一(版权申明插件)

作用:在bundle.js 中 增加版权信息,即为打包的文件添加版权申明

  • 该插件名称叫做 BannerPlugin,属于webpack自带的插件
  • 按照下面的方式来修改webpack.config.js文件:
const path = require('path')
const webpack = require('webpack')

module.exports = {
  ....
  plugins:[
    new webpack.BannerPlugin('版权相关申明信息')
  ]
}

插件二(打包html的plugin)

  • 目前,我们的index.html文件是存放在项目更睦邻居下面的
    • 我们知道,在真是发布项目时,发布的是dist文件夹中的内容,但是dist文件夹中如果没有index.html 文件,name打包的js等文件也就没有意义了。
    • 所以,我们需要将index.html 文件打包到dist文件夹中,这个时候就可以使用HtmlWebpackPlugin插件
  • HtmlWebpackPlugin插件可以为我们做这些事:
    • 自动生成一个index.html 文件(可以执行模板来生成)
    • 将打包的js文件,自动通过script标签插入到body中
  • 安装HtmlWebpackPlugin插件
npm install html-webpack-plugin@3.2.0 --save-dev 
# 注:这里如果在使用的过程中报错,则看 一下 package.json 文件中的版本号,我这里改成3.2.0 就不报错了
  • 使用插件,修改webpack.config.js 文件中的plugins部分的内容如下:
    • 这里的template表示根据什么某班来生成index.html
    • 另外,我们需要删除之前的output中添加的publicPath属性
    • 否则插入的script 标签中的src可能会有问题

配置文件如下:(webpack.config.js)

// 这个文件是配置webpack的入口和出口文件


// node.js 语法获取绝对路径
// 1. 导入path模块,从node包中找的
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry:'./src/main.js',
  output:{
    path:path.resolve(__dirname,'dist'),  // 必须是绝对路径,这里是通过node.js 的path 实现的路径的拼接
    filename:'bundle.js'  // bundle 打包
  },
  module:{
    rules:[
      {
        test: /\.css$/,
        // css-loader 只负责将css文件进行加载
        // style-loader 负责将样式添加到dom中进行操作
        // webpack 在使用多个loader的时候,是从右向左读的
        use: [ 'style-loader', 'css-loader' ]
      },
      {
        test:/\.vue$/,
        use:['vue-loader']
      },
    ]
  },
  resolve:{
    // alias: 别名
    alias:{
    //   // 当我们 导入 from vue 的时候,指向执行的路径去找文件  vue.esm.js 中包含 complier
      // 该配置项可以让js以 不是runtime-complier 发行版运行,此时可以用template
      'vue$':'vue/dist/vue.esm.js',
    //   // 配置完如下配置可以在导入的时候,可以省略后缀名
    //   extensions:['.js','.vue','.css'],
    }
  },
  plugins:[
    new webpack.BannerPlugin('最终版权信息归qzk所有'),
    // ########### 生成html #############
    new HtmlWebpackPlugin(
      {
        // 指定模板
        template: 'index.html',
      }
    ),
  ]
};

插件三(js压缩的Plugin)

  • 在项目发布之前,我们必然需要对js等文件进行压缩处理
    • 这里我们用过插件对文件进行压缩处理
    • 我们使用第三方的插件 uglifyjs-webpack-plugin, 并且指定版本号1.1.1 和CLI12 保持一致
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
  • 修改webpack.config.js 文件,使用插件:
const path = require('path');
const webpack = require('webpack');
const uglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  ...
  plugins:[
    new webpack.BannerPlugin('版权申明'),
    new uglifyJsPlugin()
  ]
}

执行重新 npm run build 后 查看打包后就是被重新压缩过

搭建本地服务器

  • webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js 搭建,内部使用express 框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果
  • 不过他是单独的某块,在webpack中使用之前需要先安装它
npm install --save-dev webpack-dev-server@2.9.1
  • Devserver 也是作为webpack中的一个选项,选项本身可以设置如下属性:
    • contentBase:为哪一个文件夹提供本地服务,某人是根文件夹,我们这里要填写 ./dist
    • port : 端口号
    • inline:页面实时刷新
    • historyApiFallback: 在SPA页面中,一栏HTML5的history模式
  • webpack.config.js 文件配置修改如下:
{
  "name": "meetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config ./build/prod.config.js",
    "dev": "webpack-dev-server --open --config ./build/dev.config.js"
  },
  "author": "qzk",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^3.5.3",
    "html-webpack-plugin": "^3.2.0",
    "style-loader": "^1.2.1",
    "uglifyjs-webpack-plugin": "^1.1.1",
    "vue-loader": "^13.7.3",
    "vue-template-compiler": "^2.6.11",
    "webpack": "^3.6.0",
    "webpack-dev-server": "^2.9.1",
    "webpack-merge": "^4.2.2"
  },
  "dependencies": {
    "vue": "^2.6.11"
  }
}

  • 我们可以再配置另外一个scripts:
    • —open 参数就表示直接打开浏览器
  • 此时配置完成后启动项目就应该使用 如下命令:
# 相对路径(不是最终的方案)
./node_modules/.bin/webpack-dev-server
// 这个文件是配置webpack的入口和出口文件


// node.js 语法获取绝对路径
// 1. 导入path模块,从node包中找的
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const uglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
 ...
  devServer:{
    // 这个server服务于哪一个文件夹
    contentBase:'./dist',
    // 实时监听变化,更新
    inline:true,
    // 指定端口
    port:8008
  }
};

最后就可以通过如下命令来执行了

npm run dev

webpack中配置文件的分离

npm install webpack-merge --save-dev

在实际开发与生产中,我们所依赖的配置文件,放在与src同级的build文件夹下一般分为:

  • base.config.js ——生产环境和开发环境都依赖的一些配置文件
  • prod.config.js ——生产环境需要,但是开发环境不需要的配置
  • dev.config.js ——开发环境需要的,生产环境不需要的配置文件

base.config.js

// 这个文件是配置webpack的入口和出口文件


// node.js 语法获取绝对路径
// 1. 导入path模块,从node包中找的
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry:'./src/main.js',
  output:{
    path:path.resolve(__dirname,'../dist'),  // 必须是绝对路径,这里是通过node.js 的path 实现的路径的拼接
    filename:'bundle.js'  // bundle 打包
  },
  module:{
    rules:[
      {
        test: /\.css$/,
        // css-loader 只负责将css文件进行加载
        // style-loader 负责将样式添加到dom中进行操作
        // webpack 在使用多个loader的时候,是从右向左读的
        use: [ 'style-loader', 'css-loader' ]
      },
      {
        test:/\.vue$/,
        use:['vue-loader']
      },
    ]
  },
  resolve:{
    // alias: 别名
    alias:{
      //   // 当我们 导入 from vue 的时候,指向执行的路径去找文件  vue.esm.js 中包含 complier
      // 该配置项可以让js以 不是runtime-complier 发行版运行,此时可以用template
      'vue$':'vue/dist/vue.esm.js',
      //   // 配置完如下配置可以在导入的时候,可以省略后缀名
      //   extensions:['.js','.vue','.css'],
    }
  },
  plugins:[
    new webpack.BannerPlugin('最终版权信息归qzk所有'),
    new HtmlWebpackPlugin(
      {
        // 指定模板
        template: 'index.html',
      }
    ),
  ],
  
};

prod.config.js

// node.js 语法获取绝对路径
// 1. 导入path模块,从node包中找的
const uglifyJsPlugin = require('uglifyjs-webpack-plugin');
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config');

module.exports = webpackMerge(baseConfig,{
  plugins:[
    new uglifyJsPlugin(),
  ],
});

dev.config.js

const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config');

module.exports = webpackMerge(baseConfig,{

  // 开发时依赖,但是生产时不依赖,所以不能放在base里面
  devServer:{
    // 这个server服务于哪一个文件夹
    contentBase:'./dist',
    // 实时监听变化,更新
    inline:true,
    // 指定端口
    port:8008
  }
});

然后在package.json 中配置 script

{
  "name": "meetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    # 配置生产时的依赖的 webpack.config.js
    "build": "webpack --config ./build/prod.config.js",
    # 配置 开发时的依赖的 webpack.config.js
    "dev": "webpack-dev-server --open --config ./build/dev.config.js"
  },
  "author": "qzk",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^3.5.3",
    "html-webpack-plugin": "^3.2.0",
    "style-loader": "^1.2.1",
    "uglifyjs-webpack-plugin": "^1.1.1",
    "vue-loader": "^13.7.3",
    "vue-template-compiler": "^2.6.11",
    "webpack": "^3.6.0",
    "webpack-dev-server": "^2.9.1",
    "webpack-merge": "^4.2.2"
  },
  "dependencies": {
    "vue": "^2.6.11"
  }
}

推荐阅读