模块化思想
// 1最早期就只是html和css处理网页
// 2发明一种语言来操作html和css js
// 3早期只是在html文件里直接在script标签里写一些脚本代码
// 4随着Ajax的出现,慢慢形成了前后端的分离
// 5客户端需要完成的事情越来愈多,代码量与日俱增
// 6为了应对代码量的增加,通常会将代码组织在多个js文件中,进行维护,就会出现许多问题
首先,当我们编写代码时,不通过模块化的思想想要引入一个js,通常是在html文件中创建一个script标签,引入我们需要的js,如果我们引入的是自己手写的js,在过个js文件中,或者多人合作开发时候,很容易发生变量重名的冲突。
// 变量命名冲突
// a.js 小明开发的
var a = true;
// b.js 小红开发的
var a = false
// index.html 中同时引入a.js、b.js后,小明记得自己的a变量是true
//c.js //小明继续开发
if(a){
console.log('我定义的a变量是true')
}
这样就报错了,小明不知道自己的变量被修改了,所以模块化思想之前很容易造成变量命名冲突的问题
所以必须解决这种问题,通过一些方法去避免这些错误,比如:匿名函数,但匿名函数又会发生每个js文件中的作用域私有,而代码不可发生复用的问题,因此又需要想方法解决,例如:
// a.js
var moudleA = (function() {
const obj = {}
const a = '我是模块A中的变量a'
obj.a = a
return obj // 将匿名函数中的变量暴露出去,实现代码复用
})()
// b.js
(function() {
console.log(moudleA.a) // 引用a中的变量,并且解决变量重名
})()
// index.html 中同时引入a.js、b.js
并且,这种导入方式对js插入顺序依赖性很强,一般公司多人开发,不同的开发人员引入不同的js文件,插入位置错误发生的报错。
但不可否认,通过匿名函数将变量暴露出去这种方式,就是最基础的模块封装。当然现在对于前端模块化已经有了很多规范:Common.js、AMD、CMD、ES6中的Modules。
总结:
0代码复杂化带来的问题
1为什么需要模块化
2模块化方案
3es6之前的方案
4处理模块依赖,整合打包
5不仅仅能处理js,其他html,css,图片,json也可以模块化处理
什么是webpack?
简单通俗的说webpack就是一个前端自动化工具 模块 打包
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
它是依赖于node环境的
官网:
https://www.webpackjs.com/concepts/
搭建vuecli
1先安装node环境
node -v
npm -v
查看版本
2新建文件夹vuecli,并初始化
npm init -y
文件夹是中文名的话,这样会报错,需要npm init回车然后填写名称,其他信息一路回车即可,然后熟悉的package.json两兄弟文件就在根目录中出来了
npm安装是缩写模式, 简单说下:
-D 为 --save-dev 开发环境中使用
-S 为 --save 生产环境中使用
-g 为 --global 全局安装
安装npm i webpack webpack-cli -D
我之前已经安装过全局的了
为啥在项目中还要安装本地webpack,而不是直接用全局的?
当你全局安装了webpack, 你使用指令webpack打包又先调用的是你全局的webpack。 毕竟你今天安装的webpack是这个版本,不能保证以后谁拿你代码一运行调用他电脑下载的webpack版本,beng,满屏飘红就出来了。因为当时做项目时的webpack版本不一样,当你克隆下来时,你就会把当时的webpack版本也克隆下来,再安装时候,就不会出现版本冲突了 所以保险点,项目都安装自己的webpack,版本不会冲突。
3测试webpack打包使用
新建文件夹dist和文件mian.js和index.html
index.html文件引入打包后的文件 命名为bundle.js如图
maian.js输入测试代码
在终端输入命名 版本不同命令输入也不同 注意
webpack main.js -o dist/bundle.js
会生成如图
测试代码也能成功
注意:此时的webpack命令是调用全局的webpack
当你安装好webpack后执行打包指令后, 执行"webpack xxxx"时要注意,此时如果你安装了全局webpack,任然调用的是你全局的而不是项目自己的,你项目调用自己的webpack指令应该是./node_modules/.bin/webpack xxxxx
为了解决该问题,我们可以添加webpack.config.js
4添加webpack.config.js文件
// webpack.config.js
const path = require("path") //node自带模块 引入路径模块
module.exports = {
entry: "./main.js", // 入口
output: {
path: path.resolve(__dirname, 'dist'), // 出口。必须为绝对路径,所以借助node的path模块 __dirname保存的是当前文件的路径
filename: 'bundle.js' // 打包后文件名
},
}
// 意思就是:我根目录有个main.js文件,里面导入了好多东西,帮我打包到我目录里面的dist文件下bundle.js文件里
// package.json
并且还需要更改一下package.json文件中的scripts属性
{
...
scripts: {
...
"build": "webpack" // build可以随便取,如: 叫xxx,终端运行 npm run xxx即可
//执行脚本"build": "webpack"时候,它会优先找本地的webpack,
//只要实在终端直接输入webpack打包都是使用的全局的,所以为了解决这个问题,用脚本这样会优先找本地的
}
...
}
// 意思: 以后我直接在终端运行一个叫build的指令去调用webpack打包, 并且通过该指令, 会自动帮我们调用开发环境中的webpack打包
当运行npm run build
时,webpack会看看我们根目录是不是有一个叫webpack.config.js的文件,然后读取运行其中的配置。
弄完这一步,最后将index.html中引入的main.js改为bundle.js后,我们可以愉快的将各个js文件当成模块,各种require、import、、、,尽情导入导出
比如,我这里在src文件夹中新建js文件夹,添加info.js、mainUnit.js然后再main.js中引入并使用
loader的使用
webpack并不能识别许多文件类型,我们需要通过各种各样的loader,来帮webpack识别。
接下来做css相关,图片相关的loader,新建文件如下
在main.js中引入 require("xxx.css")或者import "xxx.less",然后一运行报错
5引入css和less相关loader
进入webpack官网, 点击导航中的LOADERS,点击左边导航的样式,然后就可以根据需求对照文档安装和配置你需要的样式相关loader了
我这里安装css和less相关的loader,npm i style-loader css-loader less-loader less -D
因为loader基本用于开发环境, 所以安装一般都为--save-dev
// webpack.config.js
module.exports = {
...
module:{
rules: [
{
test: /.css$/,
// css-loader 只负责解析css,并不负责插入样式到页面
// style-loader 负责将样式插入页面中
// 使用多个loader时,从右往左调用
use: ['style-loader','css-loader']
},
{
test: /.less$/,
use: [{ // use中如需配置其他options 可以使用Object形式, 否则不配置可直接用Array形式,同上css-loader
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "less-loader"
}]
},
]
}
...
}
5引入图片相关loader
在网上随便找2张一大一小图片
npm install --save-dev url-loader
// webpack.config.js
module.exports = {
...
rules: [
...
{
test: /.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
// 当加载图片,小于limit时,会将图片编译成base64字符串形式
// 当加载图片,大于limit时,需要安装file-loader进行加载,加载图片会放入你打包输出的文件目录
limit: 8192 // 8192 / 1024 = xKB
}
}]
}
...
]
...
}
limit属性说明如上方注释,当图片小于limit设定的值时以base64字符串形式插入在打包的js中,此时没问题。
但是,一旦大于设定值,webpack会报错,需要安装file-loader,安装即可,不需要单独配置。
然后wenpack会将引入图片完整打包放入dist文件夹目录下,名称为32位hash值,并将开发环境中引用的图片路径替换为打包生成的图片,而此时index.html引用的为开发目录中(即img文件夹下)的图片,所以打包后再运行index.html发现背景图片不见了
所以这时我们需要当图片大于limit设定值时的打包后页面引入路径更改为dist/xxxxx,好的,进入webpack.config.js,在其中output属性中添加publicPath属性
npm install --save-dev file-loader
// webpack.config.js
module.exports = {
...
output: {
...
// 添加该属性,以后打包文件所有涉及到url的东西,都会自动在路径前添加 dist/
publicPath: 'dist/'
}
...
}
我们通常并不希望,所有的img全部打包在dist文件夹下,而是希望放在dist/img文件夹中,并且希望图片保持原名,但怕重名,还需要加点hash值。
因此,我们可以继续配置url-loader规则
// webpack.config.js
module.exports = {
...
rules: [
...
{
test: /.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192 ,
// 当不希望它打包直接放入dist文件中时,可以添加name属性,
// 当需要保存原名时可以添加[name]
// 当需要防止重名又不需要太长的hash值时可以添加[hash: x] x为你需要hash值位数
name: 'img/[name].[hash:8].[ext]'
}
}]
}
...
]
...
}
因为之前有publicPath配置,所以打包运行index.html页面图片引入路径仍然为dist/img/xxxx.xxx
7ES6转ES5
完成上面一步之后,领导打开他很久没更新的浏览器,发现页面并没有出来,打开控制台一看,全是ES6语法报错,然后立马说:“你这打包不对劲啊,浏览器版本一低就各种报错,我们不能保证用户都使用可以识别ES6语法的浏览器,代码应该要将老旧浏览器都兼容啊。”
好吧,满足他的需求,打开浏览器搜索babel,进入中文官网,点击设置选择Webpack,对照文档在编辑器中一顿输出。
npm install --save-dev babel-loader @babel/core @babel/preset-env
安装完成后,在webpack.config.js中添加规则:
// webpack.config.js
module.exports = {
...
rules: [
...
{
test: /.js$/,
exclude: /node_modules/, // 排除的目录
// 使用babel-loader将ES6代码转为ES5,做浏览器兼容
// 同时需要建立.babelrc文件,调用@babel/preset-env插件将E6转为E5S
loader: "babel-loader"
}
...
]
...
}
此时,babel-loader已经可以将ES6语法识别,但是打包将ES6转ES5还需要@babel/preset-env插件,所以我们要新建一个名为.babelrc的babel配置文件使用该转译插件:
// .babelrc
{
"presets": ["@babel/preset-env"]
}
9使用Vue
正准备执行回家程序操作,领导叫住说:“项目前端框架要用vue,就用你那玩意搞,正好可以打包。”得,继续搭vue吧。
npm i vue -S
因为vue不仅是在开发环境中使用,并且打包后依然需要依赖vue,所有安装在生成环境中。
安装之后,在main.js中使用一下吧
// main.js
import Vue from "vue";
new Vue({
el: "#app",
data: {
msg: "哈哈,使用了Vue"
}
})
// 然后在index.html中使用一下
// index.html
...
<div id="app">
<h2>{{ msg }}</h2>
</div>
...
好吧,main.js中引入的vue模块,使用的是runtime-only版本的,该版本有vue运行代码,但没有编译template的代码。
那咋办,换个vue模块引入的版本呗,打开webpack.config.js。
// webpack.config.js
module.exports = {
...
// 设置模块如何被解析
resolve: {
// 当安装vue时,默认使用的是runtime-only版本,此版本只含有vue运行的代码,不包含编译template的代码
// 需要重新更换含有runtime-compiler的版本,因为runtime-complier含有complier代码可以用于编译template
// alias(别名): 用别名代替前面的路径,不是省略,而是用别名代替前面的长路径
// 如下,当main.js中import Vue from "vue"时,因为vue是别名,所以实际为import Vue from "vue/dist/vue.esm.js"
// 别名好处是webpack直接会去别名对应的目录去查找模块,减少了webpack自己去按目录查找模块的时间
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
...
}
属性解释如上图,语文好的去官方文档看,反正我是理解不了它说的啥,文档说点白话,通俗易懂不好吗。
简单说alias就是拼接导入模块的路径,emmm,还是举例吧,如下:
// webpack.config.js
...
alias: {
'vue$': 'vue/dist/vue.esm.js' // 这是别名vue
}
...
// main.js
import Vue from "vue" <==> import Vue from "vue/dist/vue.esm.js"
import Vue from "vue/xxx/xxx" <==> import Vue from "vue/dist/vue.esm.js/xxx/xxx"
好了,应该懂了,反正也是写我自己看的,你们不理解百度去吧。
在我这其实是将alias当成vue模块引入版本重定向,当引入vue,默认引入vue.runtime.common.js文件,而我将引入文件重定向为vue.esm.js。
我怎么知道默认引入哪个版本的?
打开node_modules/vue/package.json,查看其中main属性,就是vue模块默认引入的版本。
其他版本,在node_modules/vue/dist文件夹中。
到这一步,vue配置就完成了。
10vue中template的封装
注意代码的演变
代码抽离1
// main.js
import Vue from "vue";
new Vue({
el: "#app",
template:`<div>{{msg}}</div>`
data: {
msg: "哈哈,使用了Vue"
}
})
// 然后在index.html中使用一下
// index.html
...
<div id="app">
</div>
...
代码抽离二
main.js
const App = {
template: `<div>{{msg}}</div>`,
data() {
return {
msg: "哈哈,使用了Vue123"
}
}
}
import Vue from "vue";
new Vue({
el: "#app",
template:`<App></App>`,
components: {
App
}
})
// 然后在index.html中使用一下
// index.html
...
<div id="app">
</div>
...
代码抽离三
main.js
import App from './app.vue'
import Vue from "vue";
new Vue({
el: "#app",
template:`<App></App>`,
components: {
App
}
})
// 然后在index.html中使用一下
// index.html
...
<div id="app">
</div>
...
// app.vue
<template>
<div class='app'>
<div>{{msg}}</div>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
msg: "哈哈,使用了Vue1235"
}
},
mounted() { },
watch: {},
computed: {},
methods: {},
components: {}
};
</script>
<style lang='less' scoped='scoped'>
</style>
注意 会遇到两个问题
第一
使用vue文件需要安装vue-loader
cnpm i vue-loader vue-template-compiler -D
第二
vue-loader版本问题
错误是指vue-loader在14版本以上,需要安装另外的插件
方法一:
进入package.json文件中,找到vue-loader的版本
^13.0.0指会自动匹配13.x.x中的最新版本,但是不会匹配到14.0.0
和^(插入符号)一对还有一个符号~(波浪符号)
~13.3.0指会匹配更新到13.3.x的最新版本,但不会更新到13.4.0
然后npm install
方法二:
在webpack.config.js文件中配置以下
const VueLoaderPlugin = require('vue-loader/lib/plugin');
plugins: [
new VueLoaderPlugin()
]
之后就可以使用vue组件 路由 进行基本的开发了