对于全局变量同名的早期解决方案: 闭包(匿名函数)
将我们一个文件中的代码都放在一个匿名函数里面,形成一个闭包,这样,不同文件之间的变量就不会重名了
但是,这样会导致另外一个问题, 代码的复用性变得十分低,我想在另外一个文件引用之前的变量,抱歉,做不到
这时候,模块化的雏形就有了,我们可以在闭包中创建一个obj对象,将我们想要传递的东西都放进去,然后return obj,同时,我们不能再用匿名函数了,给我们的闭包函数定义一个名字,这样别的文件通过调用这个函数就可以接收到这个obj,同时还可以使用我们想要的变量或者方法了
//给闭包函数命名
var module = (function (){
var obj = {
};
var flag = true;
function sum(num1,num2) {
return sum1 + sum2;
}
obj.flag = flag;
obj.sum = sum;
return obj;
})()
//这是另一个闭包函数
(function(){
//我想要调用flag
var flag = module.flag;
})()
这就是模块的最基础的封装事实上的模块的封装还有很多高级的话题
常见的模块化规范
模块化有两个核心: 导入和导出
在Node环境中,就可以使用这种语法
CommonJS的导出
moudle.exports = {
flag: true,
test(a,b){
return a+b;
},
demo(a,b){
return a+b;
}
}
CommonJS的导入
//CommonJS的模块,这里相当于对对象的解构
let {
test , demo , flag} = require('mouduleA');
//等同于
let a = require('mouduleA');
let test = a.test;
let demo = a.demo;
let flag = a.flag;
//index文件
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h2>我就是来搞笑的h2>
<script src="bbb.js" type="module">script>
<script src="aaa.js" type="module">script>
body>
html>
注意我在script标签加入了
type="module"
这段代码,意思就是将这对应的文件当作一个模块使用
这个js文件用来演示导出
//aaa.js
let flag = true;
let name = '小明';
let age = 20;
function sum(a, b) {
return a + b;
}
if (flag) {
console.log(sum(20,30));
}
//现在我想要用ES6的export
//导出方式1
export {
flag, sum }
//导出方式2
export var num1 = 1000;
export function shout(){
console.log("我是你爹!");
}
export class person {
aa;
run() {
console.log('我在跑步')
}
}
这个js文件用来演示导入
//bbb.js
//这个文件里面我想使用aaa.js里面的flag
import {
flag , sum} from './aaa.js';
if (flag){
console.log("小明真是个天才 , 他知道 1+1 =" + sum(1,1));
}
import {
person } from './aaa.js';
let aaa = new person();
aaa.run();//我在跑步
aaa.aa = '你爹';
console.log(aaa.aa);//你爹
还有可以导出所有的语法import * from 'xxx.js'
有时候,我们想要将引入的东西自定义命名,那么我们就用到了export default
//导出的文件代码
const address = '北京市';
const number = 123124;
//这个使用的次数只能是一次,可以导出变量,对象,函数等
export default address;
//导入的文件代码
import addr from './exportdefault.js';
console.log(addr);//这里的addr就是导出的address,名字是我们自定义的
//输出结果就是北京市
本质上来讲,他是一个现代的JS应用的静态模块打包工具
我们从两点来解释上面那句话: 模块和打包
安装webpack首先需要安装Node.js, Node.js 自带了软件包管理工具(npm [node passage manager])
全局安装
npm install webpack -g
局部安装: –save-dev是开发时的依赖,项目打包之后不需要继续使用
npm install webpack --save-dev
为什么安装全局之后,还需要局部安装呢?
package.json
中定义scripts时, 其中包含了webpack命令,那么使用的是局部webpack这里我们安装的是webpack3.6.0,因为它对应的cli2脚手架更容易让我们看见cli2对webpack的配置
文件结构
打包命令 : webpack ./src/main.js ./dist/bundle.js
(这句话的意思就是将src/main.js
打包, 打包在dist
目录下,生成bundle.js
文件)
注意: 我们一般只用打包一个main.js就行了,因为webpack会自动将main导入的所有依赖,他所引入的依赖的依赖,…等等都一起打包了,相当于main.js就是一个入口,webpack实际上打包了所有有联系的文件
//main.js
import aaa from './mathUtils.js';
console.log(aaa.add(20,30));
console.log(aaa.mul(20,30));
//mathUtils.js
export default {
add(a, b) {
return a + b;
},
mul(a, b) {
return a * b;
}
}
我们可以发现,上面的打包命令没有包含
MathUtils.js
,但是却成功一起打包了
我们只需要在index.html 下引用 我们上面生成的bundle.js文件就可以了
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<script src="dist/bundle.js">script>
body>
html>
//输出的结果就是50,600
刚才我觉得我的打包命令每次都要输入太麻烦了,我想要只输入webpack,就能够实现刚才的指令
这里,我们通过配置就能够实现
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
//这里要写绝对路径,我们这里最好获取动态的路径
//下面的这个__dirname是node的东西,它代表项目的根目录的绝对路径
path: path.resolve( __dirname,'dist'),
filename: 'bundle.js'
},
}
有了这个,我们只用在终端输入webpack就可以直接快捷打包了
里面配置了一些项目的信息,npm包管理的文件(暂时用不上,后面才会用上)
使用npm init
命令来建立package.json配置文件、
npm run build
上面那么,我们在这个文件中的script
里面加上"build": "webpack"
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "CJY",
"license": "ISC"
}
同理, 上面那句话的
"test": "echo \"Error: no test specified\" && exit 1"
意思就是我们在终端输入的 npm run test 等同于 在终端输入echo \"Error: no test specified\" && exit 1
对于上面这段代码,我有想说的,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
}
//这里面的命令,其实优先调用的是局部的webpack的版本(即局部安装,运行时依赖的webpack版本),要是没有运行时依赖的webpack,就会调用我们全局安装的webpack的命令
在实际开发中,我们电脑中的webpack版本和我们做的项目的webpack需要的版本往往是不一样的,所以安装局部依赖很重要
注意,就算我们安装了局部依赖,但是在终端或者cmd中,如果我们直接输入webpack,那么还是会默认调用全局的webpack , 只有当我们输入npm run build
的时候,调用的是局部的
我们也要将css文件作为一个模块打包进js文件中
我们来看看样式有什么loader
实现步骤
安装css-loader
和style-loader
前者作用:加载 CSS 文件并解析 import 的 CSS 文件,最终返回 CSS 代码
后者作用: 将模块导出的内容作为样式并添加到 DOM 中
//输入
npm install --save-dev css-loader
npm install --save-dev style-loader
在webpack.config.js
文件中添加下面的代码
module: {
rules: [
{
test: /\.css$/i,
//是用loader的时候,是从右向左读取的
use: ['style-loader', 'css-loader'],
},
],
},
在main.js
文件中添加依赖
require('./css/xx.css');
运行打包代码,就ok了
注意: 如果你的css-loader
的版本太高,而webpack版本比较低,那么就会报错,报错内容为this.getResolve is not a function
除了css和js文件,我想要在项目中是用less,sass,来写样式,webpack是否可以帮助我们做到呢?
步骤如下
创建一个less文件
在我们的main.js中引入
安装less-loader
和style-loader
和less
在webpack.config.js
文件的rules数组中添加下面的东西
{
test: /\.less$/i,
loader: [
// compiles Less to CSS
"style-loader",
"css-loader",
"less-loader",
],
},
运行即可
注意: 在js中,谁的css文件后引入,权重相同的情况下,谁的样式就会优先显示
我们看看文件有什么loader
现在1,3,4 都合并成为一个ref-loader
了
我们这里使用url-loader
它的作用 : A loader for webpack which transforms files into base64 URIs. (转化为base64编码)
安装url-loader
和file-loader
在webpack.config.js
中添加下列代码
{
test: /\.(png|jpg|gif|jpeg)$/i,
use: [
{
loader: 'url-loader',
options: {
//当图片大小小于limit的时候,会将图片编码为base64格式,如果大于,那么就保留图片原先的格式,但是我们需要使用file-loader来加载这个图片
limit: 819200,
},
},
],
},
注意: 当我们使用file-loader的时候,由于文件没有转化为base64,所以他是以文件的形式单独存在,所以,打包的时候,也不能打包进js文件里面,要单独打包,file-loader自动将打包的图片生成到了dist文件夹中,名字是hash生成的
我们能够在这个配置文件中的output中添加publicPath: 'dist/'
,这样所有有关url的路径都会自动在最前面加上这个前缀
在css中添加图片的位置
body {
background: pink url("../img/1.png") no-repeat;
}
运行
在图片的大小小于limit的时候,我们看看图片的路径张什么样
我们会发现,图片不是路径,他就是一串编码
大于limit的时候,看看图片的路径
我们可以看到已经变成一个图片的路径了,图片被单独保留下来了
图片默认名字是hash生成了名字,但是,在开发中,对打包的图片的名字和保留的路径往往有要求
options有name属性,name属性有下面的选项
代码示例
{
test: /\.(png|jpg|gif|jpeg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
//我们引用的时候不用担心这里会引发找不到图片路径的问题
name: 'img/[name].[hash:8].[ext]'
},
},
],
},
这样,打包的图片就会自动生成在
idst/img
文件夹下,同时,文件的名字是图片原本的名字.hash前8位.原来的后缀名
下面是webpack与语法转换相关的loader
我们这里就来讲讲babel -loader
: 它可以将所有ES5+的代码打包成为ES5的代码
步骤
安装babel-loader
: npm install -D babel-loader @babel/core @babel/preset-env webpack
webpack.config.js
文件中添加下面的代码
{
test: /\.m?js$/,
//这句话的意思就是排除这两个文件夹
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
运行
项目开发中,我们使用的是vue文件,所以我们要配置
步骤
npm安装vue: npm install vue --save
,我们这里安装的就是全局依赖,并不是开发时依赖
在main.js
里面引入vue,同时在index.html
中添加挂载的根元素
//main.js中引入vue
import Vue from 'vue';
const app = new Vue({
el: '#app',
data: {
message: '我是你爹!'
}
})
如果运行的vue是runtime-only
版本(这个版本不支持包含模板),我们要使用runtime-cpmpiler
版本(可以有template),那么我们就在webpack配置文件中添加下列代码
resolve: {
alias: {
//vue指向一个具体的文件夹
'vue$': 'vue/dist/vue.esm.js'
}
}
//注意:这个resolve是和entry,output等并列的
打包运行即可
我们是用vue后缀的文件来疯转一个组件
有什么作用?
main.js
什么都不用写,只用负责引入vue组件就行了
//main.js
import Vue from 'vue'
import App from './vue/App.vue'
require('./css/special.less');
require('./css/common.css');
new Vue({
el: '#app',
//这行代码至关重要
template: ` `,
data: {
},
//这行代码也很重要
components: {
App
}
});
引入vue-loader
和vue-template-compiler
,并在webpack配置文件里面加上
{
test: /\.vue$/,
use: ['vue-loader']
}
在index.html
中我们只用负责写一个div就行了
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
div>
<script src="dist/bundle.js">script>
body>
html>
我们创建有我们的vue文件
App.vue
是所有vue组件的父组件,可以认为是组件树的根节点
//App.vue
{
{message}}
可以看到App.vue
有一个子组件,叫做cpn.vue
//cpn.vue
<template>
<div >
<h2 id="aaa">我是{
{
name }}!!!!!</h2>
<p>就这?</p>
</div>
</template>
<script>
export default {
name: "cpn",
data() {
return{
name: '我是CJY'
}
}
}
</script>
<style scoped>
#aaa {
color: aqua;
font-size: 40px;
}
</style>
来看看效果
可以看到,显示的就是App.vue模板里面的所有内容 (背景样式请忽略)
最后看看文件的结构
什么是plugin?
plugin和loader的区别
怎么使用?
webpack.config.js
里面配置插件该插件的i那个字叫做BannerPlugin
,属于webpack自带的插件
作用,每个文件最上面加上版权声明的注释
使用步骤:
因为自带,所以不用安装
修改webpack.config.js
里面的配置
//最上面先声明,顺便一提,这种导入方法就是默认在node_modules文件夹里面寻找
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.BannerPlugin('最终版权归CJY所有')
]
}
打包
效果如图
目前,我们的index.html是放在根目录下的
HtmlWebpackPlugin插件的作用
使用步骤
安装npm install html-webpack-plugin --save-dev
在webpack配置文件中的plugin
中加上下面这句话
//同时,最上面记得引入
const HtmlWebpackPlugin = require('html-webpack-plugin');
//这里是plugin数组里面添加的内容
new htmlWebpackPlugin({
template: 'index.html'
})
注意: 这里的template表示根据什么模板来生成index.html
另外,我们需要删除之前在output中的publicPath属性,否则插入的script标签中的src可能会有问题
打包,运行,我们会发现在dist文件夹下面有index.html
文件,同时,图片引入的路径问题就也解决了
项目发布之前,我们要对js文件进行压缩处理
我们使用第三方插件uglifyjs-webpack-plugin
,并指定版本号为1.1.1,和cli2保持一致
使用步骤
安装npm install [email protected] --save-dev
在webpack配置文件中添加
const uglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
new uglifyjsWebpackPlugin()