webpack-从零搭建vuecli环境

先安装 node 环境

node -v npm -v 查看版本

新建文件夹 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,版本不会冲突。

测试 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

添加 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",然后一运行报错

引入 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"
        }]
      },
  ]
 }
 ...
}

引入图片相关 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

ES6 转 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"]
}

使用 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 配置就完成了。

vue 中 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 组件 路由 进行基本的开发了

posted @ 2020-08-03 15:42  有风吹过的地方丨  阅读(315)  评论(0编辑  收藏  举报