webpack

9 篇文章 0 订阅

1 认识Webpack

1.1 什么是webpack

官方解释:
At its core, webpack is a static module bundlerfor modern JavaScript applications.
从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具。

前端模块化:

  • 在前面学习中,我已经用了大量的篇幅解释了为什么前端需要模块化。
  • 目前使用前端模块化的一些方案:AMD、CMD、CommonJS、ES6。
  • 在ES6之前,我们要想进行模块化开发,就必须借助于其他的工具,让我们可以进行模块化开发。
  • 并且在通过模块化开发完成了项目后,还需要处理模块间的各种依赖,并且将其进行整合打包。
  • 不仅仅是JavaScript文件,我们的CSS、图片、json文件等等在webpack中都可以被当做模块来使用(在后续我们会看到)。

打包:

  • 理解了webpack可以帮助我们进行模块化,并且处理模块间的各种复杂关系后,打包的概念就非常好理解了。
  • 就是将webpack中的各种资源模块进行打包合并成一个或多个包(Bundle)。
  • 并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。

1.2 Webpack和grunt/gulp的对比

  • grunt/gulp的核心是Task

    • 我们可以配置一系列的task,并且定义task要处理的事务(例如ES6、ts转化,图片压缩,scss转成css )
    • 之后让grunt/gulp来依次执行这些task ,而且让整个流程自动化
    • 所以grunt/gulp也被称为前端自动化任务管理工具。
  • 我们来看一个gulp的task

    • 下面的task就是将src下面的所有js文件转成ES5的语法。
    • 并且最终输出到dist文件夹中。
    const gulp = require('gu1p');
    const babe1 = require('gu1p-babe1');
    gulp.task( 'js ', () =>
    	gulp.src('src/* .js ')
    		.pipe(babel({
    			presets: ['es2015'])
    		}))
    		.pipe(gulp.dest('dist'))
    );
    
    
  • 什么时候用grunt/gulp呢?

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

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

1.3 webpack依赖环境–node

webpack为了可以正常运行,必须依赖node环境。
怎么安装node来着
查看自己的node版本:node -v

node环境为了可以正常的执行很多代码,必须其中包含各种依赖的包。
安装node的时候,会自动安装软件包管理工具npm(node packages manager)

2 webpack安装

  1. 全局安装webpack
    (这里先指定版本号3.6.0,因为vue cli2依赖该版本,而vue cli3 的配置被隐藏了,不好看)
    npm install webpack@3.6.0 -g (-g 代表全局 – global)

  2. 局部安装webpack(后续才需要)
    --save-dev是开发时依赖,项目打包后不需要继续使用的。

    cd对应目录
    npm install webpack@3.6.0 --save-dev
    

☆ 为什么全局安装后,还需要局部安装呢?

  • 在终端直接执行webpack命令,使用的全局安装的webpack
  • 当在package.json中定义的scripts中,包含了webpack命令时,使用的是局部webpack

3 webpack的基本使用

3.1 准备工作:创建文件和文件夹

  • 创建文件和文件夹:
    • dist文件夹:用于存放之后打包的文件
    • src文件夹:用于存放我们写的源文件
      • main.js:项目的入口文件。具体内容查看下面详情
      • mathUtils.js:定义了一些数学工具函数,可以在其他地方引用,并且使用。具体内容查看下面的详情。
      • info.js:根据ES6规范,定义了一些变量,可以在其他地方引用,并且使用。
    • index.html:浏览器打开展示的首页html
    • package.json:通过npm init生成的,npm包管理的文件(暂时没有用上,后面才会用上)
      在这里插入图片描述
      使用模块化的方式进行开发js文件:
      mathutils.js文件中的代码︰
function add(num1, num2) {
  return num1 + num2;
}
function mul(num1, num2) {
  return num1 * num2;
}

// 1.使用commenjs的模块化规范导出
module.exports = {
  add,
  mul
}

  • info.js文件中的代码︰
// 2.使用ES6的模块化规范导出
export const name = 'why';
export const age = 18;
}

  • main.js文件中的代码︰
// 1.使用commenjs的模块化规范导入
const {add, mul} = require('./mathUtils.js')
console.log(add(1, 2));
console.log(mul(1, 2));

// 2.使用ES6的模块化规范导入
import { name, age } from './info.js';
console.log(name, age);

2.2 js文件的打包

  • 使用模块化的方式开发的 js文件,它们不可以直接使用。

    • 因为如果直接在index.html引入这两个js文件,浏览器并不识别其中的模块化代码。
    • 另外,在真实项目中当有许多这样的js文件时,我们一个个引用非常麻烦,并且后期非常不方便对它们进行管理。
  • 可以使用webpack工具,对多个js文件进行打包。

    • webpack就是一个模块化的打包工具,支持我们代码中写模块化,可以对模块化的代码进行处理。(如何处理的,待会儿在原理中,我会讲解)
    • 在处理完所有模块之间的关系后,将多个js打包到一个js文件中,引入时就变得非常方便了。
  • 如何打包呢?

    • 使用cd命令进入dist和src文件夹所在的目录,使用webpack的指令即可:webpack 。./src/main.js ./dist/bundle.js
    • 其中,./src/main代表入口文件,./dist/bundle.js设置了出口路径和生成的js文件名称。
  • 打包成功 的截图如下:在这里插入图片描述

2.3 使用打包后的文件

webpack处理项目直接文件依赖,在dist文件下生成bundle.js文件。
将打包生成的的bundle.js文件在index.html中引入即可。
在这里插入图片描述

4 webpack的配置

4.1 webpack.config.js配置

每次使用webpack的命令都需要写上入口文件出口作为参数,就非常麻烦。
解决方法:将这两个参数写到配置文件webpack.config.js(名字固定)中,在运行时,直接读取。

  1. 手动创建webpack.config.js文件

    // 依赖node包,需要使用npm init建package.json文件帮忙管理node包
    const path = require('path');
    module.exports = {
      // 入口:可以是字符串/数组/对象,这里我们入口只有一个,所以写一个字符串即可
      entry: './src/main.js',
      //出口:通常是一个对象,里面至少包含两个重要属性:path和 filename
      output: {
        // 注意:path的值要求绝对路径
        // 为了动态的获取路径需要用到path包
        // path.resolve()方法拼接路径
        // __dirname是node自带的全局变量
        path: path.resolve(__dirname,'dist'),
        filename: 'bundle.js'
      }
    }
    
  2. 终端使用cd命令,进入dist和src文件夹所在的目录中,输入webpack,点击回车即可。

4.2 package.json配置

(package.json文件使用 npm init命令创建,注意name不能有中文。)
使用局部webpack
因为一个项目往往依赖特定的webpack版本,全局的版本可能和这个项目的webpack版本不一致,导出打包出现问题。 所以通常一个项目,都有自己局部的webpack。
目前,我们使用的webpack是全局的webpack(只要是在终端运行命令的,用的都是全局的),如何使用局部来打包:

  • 第一步,项目中需要安装自己局部的webpack
    • 这里我们局部安装webpack3.6.0
      (注意:webpack 是开发时依赖–只是开发时打包需要,项目打包后不需要继续使用,添加webpack时需要 添加上‘–save-dev’
      本地安装webpack后,会新增node_modules文件夹,里面都是默认安装的包。)
      (Vue CLI3中已经升级到webpack4,但是它将配置文件隐藏了起来,所以查看起来不是很方便。)
      命令如下:
	cd对应目录
	npm install webpack@3.6.0 --save-dev
  • 第二步,通过node_modules/.bin/webpack启动webpack打包
    在这里插入图片描述

package.json中定义启动
每次执行都敲这么一长串不方便,我们可以在package.json的scripts中定义自己的执行脚本。
在这里插入图片描述

执行我们的build指令
npm run build

定义脚本,添加npm run build指令到webpack的映射后,使用该命令,会优先使用本地的webpack版本,而不是全局的webpack版本。

package.json中的scripts的脚本在执行时,会按照一定的顺序寻找命令对应的位置。

  • 首先,会寻找本地的node_modules/.bin路径中对应的命令。
  • 如果没有找到,会去全局的环境变量中寻找。

5 loader的使用

5.1 什么是loader

  • webpack本身可以处理我们写的js代码,自动处理js之间相关的依赖。
  • 给webpack扩展对应的loader,就可以在开发中加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等这些转化

5.2 loader的使用

步骤:

  • 通过npm安装需要使用的loader
  • 在webpack.config.js中的module关键字下进行配置

大部分loader我们都可以在webpack的官网找到,并且学习对应的用法。
在这里插入图片描述

5.3 CSS文件处理- 准备工作

项目开发过程中,我们必然需要添加很多的样式,而样式我们往往写到一个单独的文件中。

  • 在src目录中,创建—个css文件,其中创建一个normal.css文件。
  • 我们也可以重新组织文件的目录结构,将零散的js文件放在一个js文件夹中。

normal.css中的代码非常简单,就是将body设置为red。但是,这个时候normal.css中的样式会生效吗?
口当然不会,因为我们压根就没有引用它。
webpack也不可能找到它,因为我们只有一个入口,webpack会从入口开始查找其他依赖的文件。
在入口文件中引用∶
在这里插入图片描述

在这里插入图片描述

安装loader:
npm install --save-dev css-loader
npm install --save-dev style-loader
配置loader:
在这里插入图片描述
其中:text选项中是正则表达式,意为:以.css结尾的文件。

注:具体的loader如何使用,可以参照:https://webpack.docschina.org/loaders/

6 webpack配置Vue

6.1 引入vue.js

在我们的webpack环境中集成Vue.js的步骤:

  1. 安装vue包
    注:因为我们后续是在实际项目中也会使用vue的,所以并不是开发时依赖,用--save
    npm install vue --save

  2. 导入vue包

    // 没有写路径时,会先去node_modules文件夹里找
    // 源码中导出是用的:export default Vue
    import Vue from 'vue'
    

    那么,接下来就可以按照我们之前学习的方式来使用Vue了
    在这里插入图片描述

  3. 修改vue的版本
    修改webpack的配置(webpack.config.js文件),添加如下内容即可

  resolve: {
    alias: {
      // 指向具体的文件,会先去找该文件,是有包括compiler的
      // 不设置的话,默认是指向vue.runtime.js的
      'vue$': 'vue/dist/vue.esm.js'
    }
  }
关于第3步的必要性解释:

只做第1、 2步,不修改vue的版本的话,vue版本默认是指向vue.runtime.js的。
重新打包后,运行程序:
打包过程没有任何错误。(因为只是多打包了一个vue的js文件而已)
但是运行程序,没有出现想要的效果,而且浏览器中有报错
![在这里插入图片描述](https://img-blog.csdnimg.cn/8e8439f5c52b44978f8b63fb7bff2cc3.png)
这个错误说的是我们使用的是runtime-only版本的Vue。

runtime-only和runtime-compiler的区别:
1.runtime-only ->代码中,不可以有任何的template(包括Vue实例)
2.runtime-compiler ->代码中,可以有template,因为有compiler可以用于编译template

6.2 el 和template区别(一)

正常运行之后,我们来考虑另外一个问题:

  • 如果我们希望将data中的数据显示在界面中,就必须是修改index.html
  • 如果我们后面自定义了组件,也必须修改index.html来使用组件
  • 但是html模板在之后的开发中,并不希望手动的来频繁修改,是否可以做到呢?

定义template属性:

  • 在前面的Vue实例中,我们定义了el属性,用于和index.html中的#app进行绑定,让Vue实例之后可以管理它其中的内容
  • 这里,我们可以将div元素中的{{message}}内容删掉,只保留一个基本的id为app的元素
  • 但是如果我依然希望在其中显示{{message}}的内容,应该怎么处理呢?
  • 我们可以再定义一个template属性,代码如下:
new vue({
	el: '#app',
	template: '<div id="app">{{message}}</div>' ,
	data: {
		message: 'coderwhy'
	}
})

同时有el和template属性的情况下,template的值会将el挂载到的dom替换掉。
好处是:不需要修改html代码。

6.3 el 和template区别(二)

.Vue文件封装处理
但是—个组件以一个js对象的形式进行组织和使用的时候是非常不方便的
一方面编写template模块非常的麻烦
另外一方面如果有样式的话,我们写在哪里比较合适呢?现在,我们以一种全新的方式来组织一个vue的组件
但是,这个时候这个文件可以被正确的加载吗?
必然不可以,这种特殊的文件以及特殊的格式,必须有人帮助我们处理。
谁来处理呢? vue-loader以及vue-template-compiler。
安装vue-loader和vue-template-compiler
npm install vue-loader vue-template-compiler --save-dev
修改webpack.config.js的配置文件:

{
	test: /\.vue$/ ,
	use: [ 'vue-loader']
}

7 plugin的使用

8 搭建本地服务器

8.1 本地服务器的作用

webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果

8.2 本地服务器的安装

它是一个单独的模块,在webpack中使用之前需要先安装:
npm install --save-dev webpack-dev-server@2.9.1

注:
- 这个版本需要与webpack的(3.6.1)版本相对应.
- `--dev`代表:开发时依赖,为开发时服务。
- 没有`-g`,属于局部安装。

8.3 本地服务器的配置

配置webpack中的devserver选项,设置如下属性:

  • contentBase:为哪一个文件夹提供本地服务,默认是根文件夹,我们这里要填写./dist
  • port:端口号(默认:8080)
  • inline:页面实时监听刷新
  • historyApiFallback:在SPA页面中,依赖HTML5的history模式(待补)

webpack.config.js文件配置修改如下:
在这里插入图片描述

8.4 本地服务器的启动

不可以在终端直接运行webpack-dev-server,因为之前是局部安装的,而在终端直接运行的命令,运行的是全局安装的。

可以通过相对路径下的bin目录,找到它来运行。这个方法是可行的,但是视频老师没成功,待补。

在这里插入图片描述
更简洁的方式:
在package.json文件中添加配置,再在终端中执行npm run dev,这时会优先在本地找。
在这里插入图片描述

运行成功后,点击该路径,可以打开运行的本地服务。
在这里插入图片描述
补充:

  1. 加上--open参数,设置启动本地服务器后,自动打开浏览器,不需要手动点击打开。
    在这里插入图片描述
  2. 开发阶段,不进行丑化,否则出错后,在浏览器不好进行调试。

8.5 本地服务启动成功的验证

在main.js文件中删除之前添加的document.writeln('<button>按钮')</button>),查看页面显示,该按钮被消除了(不需要再重新编译之类或者手动刷新)。
证明本地服务可以让浏览器自动刷新显示我们修改后的结果。

9 开发时和发布时依赖的配置分离

其实,得先弄清楚,哪些是开发时的依赖配置,哪些是发布时的依赖配置。(这里还不太清楚)
开发时和发布时的公共依赖:

  • Vue – 因为代码里有Vue,生产环境肯定也有

开发时依赖:

  • webpack – 只是打包工具,生成生产环境的代码。
  • loader和plugin – 对源代码进行一些处理,并生成最终代码的预处理器。

发布时依赖:

  • webpack的丑化插件
  1. 代码分离
    webpackage.config.js未分离代码:
// 依赖node包,使用npm init建package.json文件帮忙管理node包
const path = require('path');
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const UglifyjsWebpackPlugin = require('Uglifyjs-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    // path的值要求绝对路径
    // 动态的获取路径需要用到path包
    // path.resolve()方法拼接路径
    // __dirname是node自带的全局变量
    path: path.resolve(__dirname,'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.css$/ ,
        // 'css-loader 只负责将css文件进行加载
        // 'style-loader 负责将样式添加到DOM中
        use: ['style-loader','css-loader']
      },
      {
      test: /\.vue$/ ,
      use: ['vue-loader']
      }
    ]
  },
  resolve: {
    alias: {
      // 指向具体的文件,会先去找该文件,是有包括compiler的
      // 不设置的话,默认是指向vue.runtime.js的
      'vue$': 'vue/dist/vue.esm.js'
    }
  }
  plugins: [
    new webpack.BannerPlugin('最终解释权归XX所有'),
    new UglifyjsWebpackPlugin()
  ]
}

新建一个与dist、src文件夹同目录下的文件夹build,在该文件夹里新建

  • base.config.js – 放公共的配置部分–开发时+发布时。
// 依赖node包,使用npm init建package.json文件帮忙管理node包
const path = require('path');
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')


module.exports = {
  entry: './src/main.js',
  output: {
    // path的值要求绝对路径
    // 动态的获取路径需要用到path包
    // path.resolve()方法拼接路径
    // __dirname是node自带的全局变量
    path: path.resolve(__dirname,'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.css$/ ,
        // 'css-loader 只负责将css文件进行加载
        // 'style-loader 负责将样式添加到DOM中
        use: ['style-loader','css-loader']
      },
      {
      test: /\.vue$/ ,
      use: ['vue-loader']
      }
    ]
  },
  // base
 resolve: {
    alias: {
      // 指向具体的文件,会先去找该文件,是有包括compiler的
      // 不设置的话,默认是指向vue.runtime.js的
      'vue$': 'vue/dist/vue.esm.js'
    }
  }
  plugins: [
    new webpack.BannerPlugin('最终解释权归XX所有')
  ]
}
  • dev.config.js – 开发时
// 这个是干嘛的来着,就放这一个
module.exports = {
  deVServer: {
    contentBase: './dist',
    inline: true
  }
}
  • prod.config.js – 发布时
const UglifyjsWebpackPlugin = require('Uglifyjs-webpack-plugin')

module.exports = {
  plugins: [
    new UglifyjsWebpackPlugin()
  ]
}
  1. 安装合并包
    npm install webpack-merge --save-dev
  2. 导入合并包
    以dev.config.js 为例,体会合并包的使用
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')

// 合并的使用
module.exports = webpackMerge(baseConfig, {
  deVServer: {
    contentBase: './dist',
    inline: true
  }
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值