webpack的使用

webpack中的loader

loader的作用

  1. 在之前的案例中,主要是使用webpack来处理所写的JS代码,并通过webpack来自动处理他们之间的依赖。

  2. 但是在实际开发中并不只JS文件的处理,还会加载css文件、图片等,对于webpack本身来说,对于这些转化是不支持的。

  3. 所以就需要给webpack扩展对应的loader。

loader的使用

  1. 通过npm安装所需要的loader。(webpack中文官网)
  2. webpack.config.js中的modules属性下配置。

webpack的loader

css-loader 和 style-loader

当没有使用css-loader时,直接在main.js文件中引用依赖然后打包:

//normal.css
body {
	background-color: pink;
}

//main.js
const {name,age,say,run} = require('./js/info.js');

console.log(name);
console.log(age);
console.log(say);
run();

//依赖CSS文件,使得webpack打包时会处理normal.css文件
require('./css/normal.css');

控制台会输出如下错误:

合适的loader处理

所以需要安装css-loader来处理css文件。使用npm install --save-dev css-loader
💥--save-dev 为开发时依赖模块,意为只用于开发,实际项目运行时并不依赖。

rules: [
 {
   test: /\.css$/,
   use: [ 'style-loader', 'css-loader' ]
  }
]

注: 如果只是安装css-loader并打包,在DOM中并不会显示出css文件定义的效果。因为css-loader只是将css文件加载,想要将加载好的css文件渲染到DOM中,还需要安装style-loader(npm install style-loader --save-dev);

在使用use: [ 'style-loader', 'css-loader' ]这个语句时,应注意在使用多个loader时,loader的执行顺序是从右往左,所以应该将style-loader放在左边,先执行css-loader加载css文件之后,再由style-loader渲染到DOM中。

less-loader

Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。

less-loader用于处理JS文件中对less文件的依赖。

  1. 安装less-loader:使用指令npm install --save-dev less-loader less

    ⚠️注: 如需安装指定版本,需要在loader后加 @+版本号。以下同理。

  2. 在webpack.config.js文件中配置(执行顺序是自下而上)。

    {
     test: /\.less$/,
     use: [{
      loader: "style-loader"
     }, {
         loader: "css-loader"
        }, {
          	loader: "less-loader", options: {
          	strictMath: true,
          	noIeCompat: true
           }
     }]
    }
    

url-loader

作用

使用url-loader加载css样式中的一些图片等文件。

安装

使用指令:npm install --save-dev url-loader

使用

webpack.config.js中配置:

{
 test: /\.(png|jpg|gif)$/,
 use: [{
  loader: 'url-loader',
  options: {
   //当文件小于limit所定义的数值时,会将图片编译成base64字符串形式。
   //当图片大于limit定义的数值时,打包会报错,就需要使用file-loader模块进行加载。
   limit: 13000
  }
 }]
}

🔊如果插入的图片过大,就需要使用 file-loader模块进行加载。

file-loader

用于处理大文件的加载.

  1. 安装指令: npm install --save-dev file-loader

  2. 然后再次运行打包指令。

  3. 运行index.html,控制台会提示找不到文件。

  4. 是由于使用webpack打包时,webpack会把图片文件放到打包文件同一路径下直接引用,但是是直接引用,未指定前置路径。

    同一路径

    没有前置路径
  5. 在调试中将url路径改为
    url(dist/8e08b79ef4c5e855db743e16c3b5f2a1.png)
    此时页面就会正常渲染。

  6. 如果想要解决这个问题,就需要使background后的url引用路径改为dist/xxx.jpg。在webpack.config.js文件中加入publicPath: 'dist/'。意为只要涉及到url的问题,都会自动地在文件前面加上dist/

问题解决
💡当index.html文件也在dist文件夹下,
则不需要再使用 publicPath: 'dist/'指令
关于生成的文件名
  • webpack会在打包时将文件放入打包文件的同一目录下,并且会生成一个32位的hash值,防止文件命名重复。

  • 但是在实际的开发中,我们可能对打包的名字有一定的要求——比如,将所有的图片放在一个文件夹中,但是需要跟上原来的名字,同时还要防止重复。

  • 此时我们需要在options中添加一个name属性:

    • img:文件要打包的文件夹;
    • name:获取图片原来的名字,放在该位置;
    • hash:8:为了防止图片名称重复,依然使用hash,但是只保留8位;
    • ext:原来的图片扩展名。
    //使用[name]就是使用图片原有的name,使用.是将名称连接起来
    name: 'img/[name].[hash:8].[ext]'
    
  • 将原本打包好的的文件删除,然后重新打包npm run build

完成打包在img目录下的自定义图片名称

babel-loader

🏆我们上述的打包文件中会有ES6的语法,当浏览器不支持ES6时会无法正常渲染,所以我们需要使用babel-loader模块完成转换。

  • 安装:

    npm install babel-loader babel-core babel-preset-env webpack
    
  • 配置:

    {
     test: /\.js$/,
    	//由于最后打包完成并运行node依赖文件并不参加,所以使用exclude将文件排除
     exclude: /(node_modules|bower_components)/,
     use: {
     	loader: 'babel-loader',
     	options: {
    	 // presets: ['@babel/preset-env']
    		// 为什么使用2015版本不知
    		presets: ['es2015']
     	}
     }
    }
    
  • 再次运行npm run build。打包完成,然后进入打包好的文件bundle.js搜索ES6的语法(如let,const),没有搜到,说明已经成功将ES6的语法转化为ES5。
    没有const
    没有let

webpack配置Vue

Vue模块

安装

在之前的学习过程中,在项目中引用Vue大致是使用两种方法:

  1. 下载Vue.js文件,然后通过<script>标签引入;

    <script src="../js/vue.js"></script>
    
  2. 使用cdn引入

      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    

💥而这两种方法都是不符合我们的模块化开发思想的,模块化开发应该是以引入模块的方式进行使用。所以我们需要使用npm安装的方式来引入vue模块。

使用指令:

npm install vue --save

注:由于Vue在运行时也是需要依赖的,所以不需要使用–save-dev。

使用

  1. 在js文件中使用vue进行开发:

    //使用vue进行开发
    //导入vue模块,引号中的vue就是安装好的vue模块
    import Vue from 'vue';
    
    const app = new Vue({
      el: '#app',
      data: {
        msg: 'hello webpack'
      }
    })
    
  2. 在index.html文件中输入代码并执行:

    <div id="app">
      <h1>{{msg}}</h1>
    </div>
    <script src="./dist/bundle.js"></script>
    

运行时的错误-模板编译器

  1. 并没有执行,浏览器会抛出一个错误:
    正在使用vue的runtime-only版本,模板编译器不可用。

    🗨️这是由于vue模块有两个版本:runtime-onlyruntime-compiler

    • runtime-only => 代码中不可以有任何的template
    • runtime-compiler => 代码可以有template,因为有compiler用于编译template。

    🗨️因为使用的是前者打包,它其中并没有包含模板编译器,所以浏览器无法正常运行。被Vue实例el属性挂载的元素也可以看做是一个模板

  2. 解决这个问题需要在webpack.config.js文件中加入:

      resolve: {
        //别名
        alias: {
          // vue$表示以vue结尾的文件,由于默认情况下vue使用的是vue.runtime.js,所以我们需要将vue的默认使用改变从而使用runtime-compiler。
          'vue$': 'vue/dist/vue.esm.js'
        }
      }
    
    是将Vue的默认使用文件改变为vue.esm.js从而可以使用模板编译器
  3. 再次npm run build,就可以在浏览器中正常渲染啦!
    hello webpack

创建Vue时el和template的关系

在上面的代码可以正常运行后,有一个问题出现了:

❓ 当我们后续想要添加或修改data或其他属性的引用方式,我们就需要在index.html中修改相应的代码。那么有没有一种方法可以使我们在js文件中就可以修改呢?

Vue实例中的template属性

答案是我们可以在Vue实例中定义一个template属性:

  • 在之前,我们只是定义了el属性,使得Vue实例对html中一个元素进行绑定;

  • 现在我们只在html中保留一个div#app的元素,然后在Vue实例中定义一个template属性;

    const app = new Vue({
      el: '#app',
      template: `
      <div>
        <h2>{{msg}}</h2>
        <h2>{{name}}</h2>
        <button @click="btnClick">点击事件</button>
      </div>
      `,
      data: {
        msg: 'hello webpack',
        name: 'coderbut'
      },
      methods:{
        btnClick(){
          alert('alert');
        }
      }
    })
    
  • 完成之后即使html页面只有一个div#app元素,也可以正常渲染。有利于文件的分离。
    正常渲染

分离写法

在上面,使用了Vue实例中的template属性,从而使前端html文件中只有一个div#app的元素。

我们可以定义一个子组件,将属性从Vue实例中分离出来:

const App = {
  template: `
    <div>
    <h2>{{ msg }}</h2>
    <h2>{{ name }}</h2>
    <button @click="btnClick">点击事件</button>
    </div>
  `,
  data() {
    return {
      msg: 'hello webpack',
      name: 'coderbut'
    }
  },
  methods: {
    btnClick() {
      alert('alert');
    }
  }
}

然后在Vue实例中注册模板,并在实例中的template属性中使用组件。

new Vue({
  el: '#app',
  template: '<App />',
  components:{
    App
  }
})

打包并运行,这样也可以得到相同的效果

template: ‘’

模块化 - 在js文件中导出

✨除了上述在一个js文件中定义一个子组件,还可以在另一个js文件中定义并导出,然后在mian.js文件中导入。

  1. 定义一个App.js文件,并编辑。

    //App.js
    //default表示导出一个模块并且由导入者命名
    export default {
      template: `
        <div>
        <h2>{{ msg }}</h2>
        <h2>{{ name }}</h2>
        <button @click="btnClick">点击事件</button>
        </div>
      `,
      data() {
        return {
          msg: 'hello webpack',
          name: 'coderbut'
        }
      },
      methods: {
        btnClick() {
          alert('alert');
        }
      }
    }
    
    //main
    import Vue from 'vue';
    import App from './js/App'
    new Vue({
      el: '#app',
      template: '<App />',
      components:{
        App
      }
    })
    
  2. 打包并运行,依然可以得到相同的效果。

模块化 - 在.vue文件中配置

在使用vue模块中,我们可以定义后缀为.vue的文件,在里面定义属性模板,之后在js文件中引用。

  1. 首先创建一个App.vue文件。
    vue文件模板

  2. 在vue文件中编辑。

    <template>
      <div>
        <h2>{{ msg }}</h2>
        <h2>{{ name }}</h2>
        <button @click="btnClick">点击事件</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "App",
      data() {
        return {
          msg: 'hello webpack',
          name: 'coderbut'
        }
      },
      methods: {
        btnClick() {
          alert('alert');
        }
      }
    }
    </script>
    <!--可以为模板内的元素定义样式-->
    <style scoped>
    h2 {
      color: powderblue;
    }
    </style>
    
  3. 在main.js文件中导入该文件,注意此时文件需要加后缀;

    import App from './vue/App.vue';
    mport App from './vue/App.vue';
    
    new Vue({
      el: '#app',
      template: '<App />',
      components:{
        App
      }
    })
    

    💡 如果不想导入的时候加后缀,可以在webpack.config.js文件中配置resolve属性

    resolve: {
          //该属性表示可以省略的后缀名
      extensions:['.js','.css','.vue']
    }
    
  4. 此时如果直接打包会报错;
    需要使用vue-loader

  5. 我们需要安装vue-loadervue-template-compiler

    npm install vue-loader vue-template-compiler --save-dev
    

    然后在webpack.config.js文件中添加规则:

    rules: [
      {
        //意为 .vue 文件使用vue-loader处理
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
    

    🚨注:在vue-loader14版本之后,使用vue-loader需要另外配置一个插件,这次我们把vue-loader的版本改到13 。

  6. 更改vue-loader版本。

    进入package.json文件,将vue-loader的版本改为^13.0.0 。再次运行npm install

  7. 安装完成之后再次运行npm run build进行打包。

  8. 运行。
    可以正常运行,并且定义 样式也生效了

当然,在vue文件中也可以导入vue文件(套娃警告)。

  1. 定义另一个vue文件Cpn.vue

    //Cpn.vue
    <template>
      <div>
        <h1>{{ msg }}</h1>
      </div>
    </template>
    
    <script>
    export default {
      name: "Cpn",
      data() {
        return {
          msg: 'cpn template'
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    
  2. 在App.vue中导入并注册;

    components: {
        Cpn
     }
    
  3. 之后重新打包并运行,就可以看到我们在App.vue中使用的Cpn.vue的内容了。

    执行效果

webpack的plugin(插件)

什么是plugin?

🦆 plugin是插件的意思,通常是用于对某个现有的架构进行扩展;

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

plugin和loader的区别

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

👁️ plugin是插件,它是对webpack本身的扩展,是一个扩展器

plugin的使用

  1. 通过npm安装需要使用plugins(某些webpack内置的插件无需安装);
  2. 在webpack.config.js文件中plugins中配置插件。

webpack的各种plugins

BannerPlugin插件

作用

BannerPlugin是webpack的自带插件,用来为打包的文件添加版本声明。

具体使用
  1. 修改webpack.config.js文件(由于是自带插件,所以不需要安装):

    • 首先导入webpack模块

      //导入webpack
      const webpack = require('webpack');
      
    • 然后在属性中添加plugins属性并定义

      plugins: [
      	new webpack.BannerPlugin('最终版权归coderbut所有')
      ]
      
  2. 重新打包,然后在打包好的bundle.js文件中就可以看到我们用BannerPlugin定义的内容了。

    BannerPlugin

HtmlWebpackPlugin插件

目前我们的index.html是存放于根目录下的,在发布项目时,只是会发布dist文件夹,但是如果该文件夹下没有index.html文件,那么打包好的js文件也就无法使用了,所以我们需要将index.html文件也打包到dist文件夹中,这时就需要使用HtmlWerbpackPlugin插件了。

作用

▶️ 自动生成一个index.html文件(可以指定模板生成);

▶️ 将打包好的js文件,通过<script>标签插入到<body>中。

具体使用
  1. 安装插件(学习的时候安装3.2.0版本,高版本会报错)

    npm install html-webpack-plugin@3.2.0 --save-dev
    
  2. 修改webpack.config.js中的plugins内容:

    plugins: [
    	new HtmlWebpackPlugin()
    ]
    
  3. 打包,之后就可以在dist目录下看到index.html文件,并且自动引入了bundle.js文件。

    dist文件下的index.html

    自动引入了bundle.js

    注: 由于现在index和bundle文件打包在同一目录下,所以我们不再需要使用webpack.config.js文件中的publicPath属性来指定路径。

    注释掉publicPate

UglifyjsWebpackPlugin插件

作用

压缩打包好的js文件。使js文件变得可读性差。

具体使用
  1. 安装插件(安装1.1.0版本,跟着老师做,先用指定版本~不然报错没法整,也是与cli的版本对应);

    npm install uglifyjs-webpack-plugin@1.1.0 --save-dev
    
  2. 在webpack.config.js中配置;

    • 引入

      //引入UglifyWebpackPlugin插件
      const UglifyWebpackPlugin = require('uglifyjs-webpack-plugin');
      
    • 配置plugins

      new UglifyWebpackPlugin()
      
  3. 再次打包,找到bundle.js文件查看。

    压缩混淆之后

webpack-dev-server搭建本地服务器

作用

webpack提供了一个可选的基于nodejs的本地开发服务器,内部使用express框架,可以使浏览器自动刷新显示我们修改之后的结果。

使用

  1. 使用npm安装该模块(跟着老师做,先用指定版本~不然报错没法整,也是与cli的版本对应);

    npm install --save-dev webpack-dev-server@2.9.3
    
  2. 在熟悉的webpack.config.js文件中配置devserver属性:

      devServer: {
        //为哪个文件夹提供本地服务,默认根文件夹
        contentBase: './dist',
        //是否实时监听
        inline: true
        //端口号,先不配置了
        //port: 
      }
    
  3. 再去package.json中配置一个scripts

     "dev": "webpack-dev-server --open"   // --open是打开浏览器
    
  4. 然后再运行npm run dev,会启动监听并打开浏览器,此时的路径就为

    localhost:8080

  5. 实时监听效果

    实时改变样式

webpack配置文件分离

为什么这样做

在webpack.config.js文件中,我们有的配置是需要在开发时配置的,而实际运行时并不需要,比如WebpackDevServer模块、各种plugin。

具体使用

  1. 分离我们的配置文件,定义三个配置文件。

    • base.config.js:用于存储开发和运行公用的配置,即这里面的配置既是开发时依赖,也是运行时依赖;
    • dev.config.js:开发时特殊的配置放在dev配置文件里面,只是开发时需要,实际运行时不需要的配置;
    • prod.config.js:生产时(运行时)特殊的配置放在prod配置文件里面。
    //base.config.js
    const path = require('path');
    const webpack = require('webpack');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      entry: './src/main.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.vue$/,
            use: ['vue-loader']
          }
        ]
      },
      resolve: {
        alias: {
          'vue$': 'vue/dist/vue.esm.js'
        }
      },
      plugins: [
        new webpack.BannerPlugin('最终版权归coderbut所有'),
        new HtmlWebpackPlugin({
          template: 'index.html'
        })
      ],
    }
    
    //dev.config.js
    module.exports = {
      devServer: {
        contentBase: './dist',
        inline: true
      }
    }
    
    //prod.config.js
    const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
    module.exports = {
      plugins:[
        new UglifyjsWebpackPlugin()
      ]
    }
    
  2. 安装webpack-merge模块(还是低版本,教程比较老,为了学习~)

    npm install webpack-merge@4.1.5 --save-dev
    

    之后在各个文件中导入并使用

    //prod.config.js
    //导入WebpackMerge和base.config.js
    const WebpackMerge = require('webpack-merge');
    const BaseConfig = require('./base.config')
    
    const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
    //使用WebpackMerge
    //意为将第二个参数里的数据和导入的base.config.js文件合并
    module.exports = WebpackMerge(BaseConfig,{
      plugins:[
        new UglifyjsWebpackPlugin()
      ]
    });
    
    const WebpackMerge = require('webpack-merge');
    const BaseConfig = require('./base.config');
    
    module.exports = WebpackMerge(BaseConfig,{
      devServer: {
        contentBase: './dist',
        inline: true
      }
    });
    
  3. 删除webpack.config.js文件,之后运行打包程序,终端会报错;

    没有找到配置文件

  4. 此时我们需要在package.json中的script属性中配置,为其中的自定义指令指令添加额外的命令;

     //自定义配置文件
        "build": "webpack --config ./build/prod.config.js",
        "dev": "webpack-dev-server --open --config ./build/dev.config.js"
    
  5. 再次打包,就可以成功了。

  6. 但是仍然会存在一个问题,就是在打包成功之后,打包好的bundle.js文件会在build文件下新建的dist文件夹中。

    路径问题

    解决这个问题只需要进入base.config.js文件,找到当时定义的path属性,然后修改。

     entry: './src/main.js',
      output: {
        //找到上一层然后拼接dist
        path: path.resolve(__dirname, '../dist'),
        filename: 'bundle.js',
      }
    

    修改完成之后再次打包,打包好的文件就会出现在该出现的位置了(根目录下的dist文件夹)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值