• webpack-从零搭建vuecli环境


    模块化思想

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

  • 相关阅读:
    android 属性动画
    android EventBus
    android gson使用
    Date、String、Calendar类型之间的转化
    2020-08-26:裸写算法:树的非递归先序遍历。
    2020-08-25:BloomFilter的原理以及Zset的实现原理。
    2020-08-24:什么是小文件?很多小文件会有什么问题?很多小文件怎么解决?(大数据)
    2020-08-23:描述HTTPS和HTTP的区别。
    2020-08-22:I/O多路复用中select/poll/epoll的区别?
    2020-08-21:网络IO模型有哪些?
  • 原文地址:https://www.cnblogs.com/ycyc123/p/13426650.html
Copyright © 2020-2023  润新知