# webpacke模块化开发

# 一、为什么要有模块化

# 1】全局变量同名的问题。

其实可以用匿名函数来解决 (function() { })()

但是这个方法的话,代码的复用性就没办法实现。

# 2】代码的编写方式对js文件的依赖顺序几乎是强制性的。
# 3】常见的模块化规范:

CommonJS(node)、AMD、CMD,也有ES6的Modules

# 4】CommonJS(了解在webpack中需要底层支持运行)

​ ①CommonJS的导出

module.exports={
    flag:true,
    test(a,b){
    	return a+b
    },
    demo(a,b){
    	return a*b
    }
}

​ ②CommonJS的导入

//CommonJS模块
let {test,demo,flag}=require('./moduleA.js');
//等同于
let _mA=require('./moduleA.js');
let test=_mA.test;
let demo=_mA.demo;
let flag=_mA.flag;
# 5】ES6的模块化(重要)

①在主html中先模块化所有js文件

...
<script src="aaa.js" type="module"></script>
<script src="bbb.js" type="module"></script>
<script src="ccc.js" type="module"></script>

②再到相应的js文件内导出需要在其他js文件里使用的变量或者函数

//1.导出方式一
name='why',
age=18,
function sum(num1,num2){
return num1+num2
}
export{name,age,sum}

//2.导出方式二
export var name='why'
export var age=18

//3.导出函数或者类
export function sum(num1,num2){
						return num1+num2
					}
export class person{
		run(){
			console.log('嘤嘤嘤');
		}
}
//4.export default  注意:在同一个模块中不能出现多个
const address='北京市'
export default address //只能导出一个值,导入的时候可以使用不同的名字命名
import add from './xxx.js'

//5.用export default导出一个对象
export default {
const address='成都',
var num=1,
function sum(a,b){
			return a*b
		}
}
//在导入的时候可以对对象进行随意命名
import xx from './xxx.js'
然后再通过xx.address、xx.num、xx.sum(1,2)来使用变量或者函数

③最后到其他文件里面倒入

//1.基本导入
import {xxx,xxx,xxx} from "./aaa.js"
//2.统一全部导入
import * as xx from './aaa.js' 

# 二、Webpack详解

# 1、认识webpack
# 1】webpack模块化的概念:

通过模块化开发完成了项目后,还需要处理模块间的各种依赖,并且将其进行整合打包。而webpack其中一个核心就是让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖关系。而且不仅仅是JavaScript文件,我们的CSS、图片、json文件等等在webpack中都可以被当做模块来使用。

# 2】打包

就是将webpack中的各种资源模块进行打包合并成一个或多个包(bundle)。并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。

# 3】grunt/gulp和webpack的不同

①grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。

②webpack更加强调模块化开发管理,而文件压缩合并,预处理等功能,是他附带的功能。

# 2、webpack的安装
# ①安装Node.js(Node.js自带了软件包管理工具npm)
# ②可以再cmd中查看node版本(webpack依赖于node.js)
node -v
# ③全局安装webpack(这里我先指定版本号3.6.0,因为vue cli2依赖该版本)
npm install webpack@3.6.0 -g
# ④局部安装webpack

--save-dev是开发时依赖,项目打包后不需要继续使用的。

cd 对应目录
npm install webpack@3.6.0 --save-dev
# ⑤为什么全局安装后,还需要局部安装?

在终端直接执行webpack命令,使用的全局安装的webpack

当在package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack

# 三、webpack的基本使用过程

①在src中模块化开发

②在终端中:将src中的main.js文件通过webpack打包到dist文件夹下生产bundle.js文件(注意:此操作会将main.js文件中需要的所有依赖文件一起进行打包,如果没有依赖或者使用的文件就不会一起打包的)

webpack ./src/main.js ./dist/bundle.js

③在index.html文件中引用bundle.js,就可以通过webpack的支持实现模块化开发(bundle.js文件就是通过webpack生成的支持模块化的代码)

# 四、webpack的配置

①新建一个命名为webpack.config.js的配置文件

②在这个配置文件中需要导出入口路径和出口路径(绝对路径)

module.exports={
	entry:'./src/main.js',
	output:{
	path:'绝对路径,一般会配合node进行动态管理',
	filename:'bundle.js'
	}
}

③在终端中输入 webpack 执行命令(全局webpack):将src中的main.js文件通过webpack打包到dist文件夹下生产bundle.js文件(只是一种快速配置)

④package.json中定义启动

如果想要使用npm run xxx 的命令的话,需要在package.json文件中的找到scripts脚本,然后进行插入需要执行的xxx命令名称,然后对其赋值。(注意:package.json中的scripts的脚本在运行时,会按照一定的顺序寻找命令对应的位置。首先会寻找本地的node_modules/bin路径中对应的命令,如果没有找到,会去全局的环境变量中寻找。)

"scripts":{
	"dev":"xxxxxx",
	"test": "npm run unit && npm run e2e",
	"build":"webpack"
}

这里也输入的npm run build 指令,此外此方法会优先地到本地找webpack(局部安装的webpack,可能会造成webpack版本不同的问题),但是直接输入webpack命名就是使用的是全局的(只要在终端里面写命令就是全局的)

# 五、loader

我们之前用webpack来处理写的js代码,并且webpack会自动处理js之间相关的依赖。我们其实也需要加载css、图片,包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将jsx、.vue文件转成js文件等等。webpack本身是对这些转换是不支持的,现在需要对webpack拓展对应的loader就可以实现了。

# 一】loader使用基本过程:
# ①通过npm安装需要使用的loader
# ②在webpack.config.js中的modules关键字下进行配置
# ③在webpack中文官网中有教程

​ https://www.webpackjs.com/loaders/

# 二】webpack中使用css文件的配置:(css-loader和style-loader)

css-loader:解析 CSS 文件后,使用import加载,并且返回CSS代码

style-loader:将模块的导出作为样式添加到DOM中

# 1、在main.js中需要依赖css文件
require('./css/xxx.css')
# 2、通过npm安装需要使用的css-loader和style-loader
npm install --save-dev css-loader
npm install style-loader --save-dev
# 3、在webpack.config.js中加一个module对象
module.exports = {
  module: {
    rules: [
      {	//正则表达式:匹配所有的css文件,其中\.是对“.”进行转义,$是结束符
        test: /\.css$/,
          //css-loader只负责将css文件进行加载,不负责解析
          //style-loader负责将样式添加到DOM中
          //*重要*:使用多个loader时,是从右向左读取,这里就是先使用style-loader,再使用css-loader
        use: ['style-loader','css-loader']
      }
    ]
  }
}
# 4、npm run build打包在这里插入图片描述

在这里插入图片描述

# 三】webpack中less文件处理(less-loader)

如果我们希望在项目中使用less、scss、stylus来写格式,webpack也可以帮我们进行处理。

# 1、创建一个.less文件
# 2、在main.js中创建依赖
require('./css/xxx.less')
# 3、安装less-loader(对less文件进行加载)和less(把less转化成css过程需要用到的文件)
npm install --save-dev less-loader less
# 4、 在webpack.config.js中添加module对象然后设置如下:
module.exports = {
    module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader','css-loader']
      },
      {
        test: /\.less$/,
        use: [{
            loader: "style-loader" // creates style nodes from JS strings
            }, {
            loader: "css-loader" // translates CSS into CommonJS
            }, {
            loader: "less-loader" // compiles Less to CSS
            }]	//从后往前的顺序进行读取
       }
    ]
  }
}
# 四】webpack中图片文件的处理(url-loader和file-loader)
# 1、在项目中导入一张图
# 2、在css中用url的方式引用一张图
# 3、安装url-loader
npm install --save-dev url-loader
# 4、在webpack.config.js中添加module对象然后设置如下:
module.exports = {
    module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader','css-loader']
      },
      {
        test: /\.less$/,
        use: [{
            loader: "style-loader" // creates style nodes from JS strings
            }, {
            loader: "css-loader" // translates CSS into CommonJS
            }, {
            loader: "less-loader" // compiles Less to CSS
            }]	//从后往前的顺序进行读取
       },
       {
        test: /\.(png|jpg|gif)$/,//去匹配不同的格式的图片
        use: [
          {
            loader: 'url-loader',//使用url方式文件的加载
            options: {
                //**当加载的图片小于limit时,会将图片编译成base64字符串形式
                //**如果需要加载的图片大于limit时,会使用file-loader对图片进行加载,file-loader不需要配置,只需要用npm安装就行了
              limit: 8192
            }
          }
        ]
      }
    ]
  }
}
# 5、当加载的图片小于limit时,会将图片编译成base64字符串形式。如果需要加载的图片大于limit时,会使用file-loader对图片进行加载,file-loader不需要配置,只需要用npm安装就行了
npm install --save-dev file-loader
# 6、但是这时候我们会发现此时会在dist中生成一个新的图片文件:生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名。

虽然我们现在npm run buile不会报错了,但是网页中还是不能正常显示图片的,我们按F12可以看到源码中URL()里面显示的值是"./哈希值.png",而在我们当前文件夹中是没有这个文件的,所以找不到,这个文件被打包到了dist文件夹下。

此时我们需要在webpack.config.js文件中的找到output对象对他进行添加一个publicPath:'dist/',只要写了这个东西(也就是自定义public发布目录),以后涉及到任何URL的东西,它都会在前面拼接一个dist/

module.exports={
	entry:'./src/main.js',
	output:{
	path:'绝对路径,一般会配合node进行动态管理',
	filename:'bundle.js',
	publicPath:'dist/'
	}
}
# 7、打包之后文件名称的修改

​ 需要在limit后面加name(注意里面的中括号的意思是取原来的名字,所以必须加上,是个变量)

options:{
 	limit:1000,
 	name:'img/[name].[hash:8].[ext]'
    //img:文件将要要打包到的文件夹
    //name:获取图片原来的名字,放在该位置
    //hash:8:为了防止图片名称冲突,使用hash,但只保留8位
    //ext:使用图片原来的拓展名
}

但是,我们发现图片并没有显示出来,这是因为图片使用的路径不正确

■默认情况下, webpack会将生成的路径直接返回给使用者

■但是,我们整个程序是打包在dist文件夹下的,所以这里我们需要在路径下再添加一个dist/

# 五】ES6语法处理(babel-loader)

需要提高适配性,就需要把ES6语法转成ES5语法

# 1、安装需要用到的babel-loader、babel-core、babel-preset-es2015
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
# 2、配置webpack.config.js文件
module.exports = {
    module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader','css-loader']
      },
      {
        test: /\.less$/,
        use: [{
            loader: "style-loader"
            }, {
            loader: "css-loader" 
            }, {
            loader: "less-loader"
            }]	
       },
       {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192
            }
          }
       		 ]
      	},
        {
      test: /\.js$/,//匹配js文件
            //排除文件夹有些js文件没必要弄成es5
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['es2015']
        	}
     	 }
    	}
    ]
  }
}

# 六、使用Vue的配置过程

# 1、我们项目中使用Vuejs,那么必须对其有依赖,所以先进行安装
npm install vue --save
//注意:因为我们后续实在实际项目中也会使用到vue,所以不需要加开发时依赖(-dev)
--save表示运行时依赖

1.1安装vue的三种方式

①直接下载vue.js文件

②CDN引入

③npm安装,依赖被安装到node_modules文件夹下(这个“小写”vue依赖里面,使用export default导出了Vue对象),所以直接用下列代码引用Vue

import Vue from 'vue'
//前面必须是大写的V		后面必须是vue而且没有后缀名
# 2、使用Vue进行开发
import Vue from 'vue'

const app=new Vue({
    el:'#app',
    data:{
        message:'hello webpack'
    }
})
# 3、此时打包发布的话,可能无法正常运行,存在以下问题:

在构建发布版本的时候,构建了两类版本:

①runtime-only ->代码中,不可以有任何的template(这个版本就没有包含对template进行编译的代码)

②runtime-compiler ->代码中,可以有template,因为有compiler可以用于编译template

解决方案:我们在webpack.config.js配置文件中添加以下内容

resolve:{
    alias:{//alias别名
        'vue$':'vue/dist/vue.esm.js'
    }
}

# 七、创建Vue时的template和el的关系

SPA(simple page web application) ->vue-router(前端路由)

我们需要尽可能少的修改index.html文件

①index.html中的

就只有
<div id="app"></div>

②在main.js中

# vue实例中如果同事有el和template的话,template会直接把el给替换掉
import Vue from 'vue'
new Vue({
	el:'#app',
	template:`
	<div>
	<h2>{{message}}</h2>
	</div>	
	`,
	data:{
		message:'hello'
	}
})

# 八、Vue的终极使用方案(vue-loader)

使用三层结构template,scripts,style格式的.vue文件

# Vue->js->对象->子组件->template->el
# ①如果要加载.vue文件必须要有vue-loader(加载需要)和vue-template-compiler(编译解析需要)
npm install npm install vue-loader vue-template-compiler --save-dev
# ②然后修改webpack.config.js的配置文件
{
      test:/\.vue$/,
      use:['vue-loader']
}
# ③vue-loader在15.x以上版本需要另外配置一个插件才能使用,否则出错

# 九、plugin插件

# 一】认识plugin:

webpack的plugin插件就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等。

# ①loader和plugin的区别

loader主要用于转换某些类型的模块,它是一个转换器。

plugin是插件,它是对webpack本身的拓展,是一个拓展器。

# ②plugin的使用过程

1】通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)

2】在webpack.config.js中的plugins中配置插件

# 二】BannerPlugin的使用(添加版权)

属于是webpack自带的插件

# ①按照下面的方式来修改webpack.config.js的文件
const path=require('path')
const webpack=require('webpack')
module.exports={
    ...
    plugins:[
        new webpack.BannerPlugin('最终版权归xxx所有') 
    ]
}
# ②重新打包程序:查看bundle.js文件的头部,看到如下信息:
/*! 最终版权归xxx所有 */
# 三】HtmlWebpackPlugin的使用(打包html)
# 1、意义(非webpack自带的插件)

我们现在的index.html文件是存放在项目的根目录下的,在真实项目中发布的是dist文件夹中的内容,但是dist文件夹中如果没有index.html的话,那么打包的js文件将毫无意义,所以我们需要将index.html打包到dist文件夹下,这个时候就可以使用HtmlWebpackPlugin插件

# 2、使用之后的作用效果

①自动生成一个index.html文件(可以指定模板来生成)

②将打包的js文件,自动通过script标签导入到body中

# 3、安装HtmlWebpackPlugin插件
npm install html-webpack-plugin --save-dev
# 4、使用插件,修改webpack.config.js配置文件中plugins部分的内容如下:
plugins:[
    new webpack.BannerPlugin('最终版权归xxx所有'),
	new htmlWebpackPlugin({
	  template:'index.html'
	})
]

这里的template表示根据什么模板来生成index.html(它会从webpack.config.js配置文件所在的目录进行查找"index.html")。除此之外,我们还需要删除之前在output中添加的publicPath属性,否则插入的script标签中的src可能会有问题。

# 四】UglifyjsWebpackPlugin的使用(js压缩丑化)
# 1、意义(第三方插件)

发布项目之前我们需要对js文件进行压缩

# 2、安装UglifyjsWebpackPlugin插件

指定版本号1.1.1和cli2保持一致

npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
# 3、修改webpack.config.js配置文件,使用插件:
const path=require('path')//添加依赖
const webpack=require('webpack')
const uglifyjsPlugin=require('uglifyjs-webpack-plugin')
module.exports={
    ...
    plugins:[
        new webpack.BannerPlugin('最终版权归xxx所有'),
        new uglifyjsPlugin()
    ]
}
# 4、查看打包后的bundle.js,是已经被压缩丑化过了

# 十、搭建本地服务器webpack-dev-server(可以实时监听改变)

webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果。通过把数据暂时保持在内存中来实现,不需要多次npm run build。

在vscode中可以安装live server实现

# 1、需要在webpack使用之前安装它:
npm install --save-dev webpack-dev-server@2.9.1
# 2、devServer也是作为webpack中的一个选项,选项本身可以设置如下属性:
# ■contentBase:

为哪一个文件夹提供本地服务,默认是根文件夹,我们这里需要填写./dist

# ■port:

端口号

# ■inline:

页面实时刷新

# ■historyApiFallback:

在SPA页面中,依赖HTML5的history模式

# 3、webpack.config.js文件配置修改如下:
devServer:{
	contentBase:'./dist',
	inline:true
}
# 4、此时输入webpack-dev-server是不行的,因为刚才操作的是局部安装,终端中是全局查找的,我们还需要在package.json文件配置另外一个scripts:
"dev":"webpack-dev-server --open"
//--open参数表示直接打开浏览器
# 5、此时输入npm run dev就行了,而且改变了代码的话,刷新浏览器就可以看到变化。

# 十一、webpack-merge的使用(配置文件的分离)

开发需要用到的config配置文件和发布时需要用到的config配置文件进行分离。

# 1、分类建文件base.config.js(基本),prod.config.js(发布时),dev.config.js(开发时)将webpack.config.js的内容抽离
# 2、安装webpack-merge(合并的意思)
npm install webpack-merge --save-dev
# 3、在pro.config.js中修改为
const webpackMerge=require('webpack-merge')
const baseConfig=require('./base.config')
module.exports=webpackMerge(baseConfig,{
    plugins:[...]//抽离出来的内容
})
# 4、在dev.config.js中同上方法修改为
const webpackMerge=require('webpack-merge')
const baseConfig=require('./base.config')
module.exports=webpackMerge(baseConfig,{
   ...//抽离出来的内容
})
# 5、现在终端执行npm run build是会报错的,还需要对在package.json中对build进行修改
"build":"webpack --config ./build/prod.config.js",
"dev":"webpack-dev-server --open --config ./build/dev.config.js"
//手动用--config进行指令需要找的文件名,否则webpack只会去找文件名为webpack.config.js的文件
# 6、此外还需要修改发布时的路径,修改resolve
Last Updated: 7/15/2020, 10:34:45 PM