webpack 的使用

模块化开发

为什么用模块化开发?

原因1:主要是js文件依赖于导入顺序几乎是强制性的,当导入的多个js文件使用相同的变量名时,就会出现下层变量名覆盖上层变量名情况。
解决1:使用闭包函数,形成局部作用域

(function(){
    var flag = true
})()

问题2:当使用闭包函数时,文件之间变量就不能被引用
解决2:在闭包函数内定义一个对象,并把它返回

var moduleA = (function () {
    var obj = {};
    var flag = true;
    obj.flag = flag;
    return obj
})()

这样,在其它文件下直接通过modelA.flag拿到变量,但是现在模块化已经有成熟的模板。
已存在的模板规范:

CommonJS, AMD, CMD, ES6的Modules,
模板化的核心:导入和导出,如:
CommonJS导入

module.exports = {
    flag: ture,
    test(a, b) {
        return a + b
    },
    demo(a, b){
        return a * b
    }
}

CommonJS的导入

let {test, demo, flag} = require("modelA")

// 等同于
let mA = require('moduleA');
let test = mA.test;
let demo = mA.demo;
let flag = mA.flag;

ES6中的模块化

export和import基本使用

a.js文件代码

var flag = true;
function sum(a, b) {
    return a + b
}
export {
    flag, sum
}

b.js文件下导入,全部导入可以使用*

import {sum} = from "./a.js";
console.log(sum(2, 3));

其他导出方式

导出变量

export let num = 100;

导出函数/类

export function sum(a, b) {
    return a + b
}

// 导出类(ES6语法)
export class Person() {
    run () {
        return "running...."
    }
}

export default

某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名

export default function () {
    return "export default"
}

// 导入使用
import myFunc from "./info.js"

注意: export default在同一模块中,有且只能存在一个

webpack 使用

介绍

At its core, webpack is a static module bundler for modern JavaScript applications.
从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具

主要功能:把各种模块化开发的代码,打包成大多数浏览器都能识别的代码。比如处理模块之间的关系;压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。

和grunt/gulp相比

  • grunt/gulp的核心时Task

    • 配置一系列的task,并且定义task要处理的事务
    • grunt/gulp来一次执行这些task,让整个流程自动化
    • grunt/gulp也被称为前端自动化任务管理工具
  • grunt/gulptask使用方式,把src下面的所有js文件转换成ES5的语法

const gulp = require("gulp");
const babel = require("gulp-babel");

gulp.task("js", () =>
    gulp.src("src/*.js")
        .pipe(babel({
            presets: ['es2015']
        }))
        .pipe(gulp.dest("dist"))
);
  • 什么情况下用grunt/gulp

    • 如果项目内只使用简单模块化,甚至没有用到
    • 只是需要进行简单的合并、压缩
  • grunt/gulpwebpack有什么不同

    • grunt/gulp更加强调的时前端流程的自动化
    • webpack更加强调的模块化开发管理

webpack安装

官网:https://webpack.js.org

  • 先安装node,最好是10版本以上
window下安装:直接到官网下载https://nodejs.org/zh-cn/
linux下安装指定版本:
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install nodejs
  • 安装cnpm,修改镜像源
npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 安装webpack(指定为3.6版本,用为vue2依赖该版本)
#全局安装
cnpm install webpack@3.6.0 -g

#局部安装,主要用于package.json中定义了scripts时,包含了webpack命令,那么使用的就是局部webpack'
cnpm install webpack@3.6.0 --save-dev

webpack简单使用

  • 创建以下文件夹
    • dist文件夹:用于存放之后的打包文件
    • src文件夹:用于存放我们写的源文件
      • main.js:项目的入口文件
      • info.js:可以是各种模块化方式导出
    • index.html:首页
// info.js 文件(使用ES6的module)
export const name = 'sun';
export const age = 18;


// math.js(使用CommandJS)
function add(num1, num2) {
  return num1 + num2
}
function mul(num1, num2) {
  return num1 * num2
}
module.exports = {
  add,
  mul
}

// main.js
// 使用commandJS
const {add, mul} = require('./mathUtils.js')
console.log(add(20, 30));

// 使用ES6
import {name, age, height} from "./info";
console.log(name);
console.log(age);

当代码编写完之后,将程序打包到dist文件夹内,只需要打包main.js文件,webpack会自动处理依赖关系。

webpack src/main.js dist/bundle.js

之后,直接在index.html文件内引入bundle.js文件就可以使用了

webpack.config.js配置

在项目目录下,创建webpack.config.js文件,

const path = require('path')

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'), // path是一个绝对路径
    filename: 'bundle.js'
  },
}

由于需要使用内置path模块,使用npm init来初始化生成package.json文件

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
  },
  "author": "",
  "license": "ISC" # 开源标志
把webpack和npm run bulid建立映射

需要在scripts脚本中,加上bulid

{
  "name": "meetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
}

这时候执行build时,是使用的局部webpack(终端直接使用webpack,都是全局的), 安装:cnpm install webpack@3.6.0 --save-dev,会在package.json中多了"devDependencies": {"webpack": "^3.6.0"}

webpack使用css文件的配置

主要功能:加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等
中文网站:https://www.webpackjs.com/loaders/

  • 安装
cnpm install css-loader --save-dev
  • webpack.config.js配置
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      }
    ]
  }}
  • 注意事项
    • css-loader只负责将css文件经行加载,不负责渲染
    • 使用style-loacer负责将样式添加到DOM中
    • 使用多个loader时,加载顺序是从右往左,需要先加载css-loader

webpack 相关文件处理

less、scss、stylus文件处理

定义一个less文件

@fontSize: 50px;
@fontColor: red;

body {
   font-size: @fontSize;
   color: @fontColor;
}

也是需要加载loader,

$ npm install less-loader less --save-dev

less是转换器,把
webpack下配置

module.exports = {
    module: {
        rules: [
            {
                test: /\.less$/,
                use: [
                    {
                        loader: 'style-loader', // creates style nodes from JS strings
                    },
                    {
                        loader: 'css-loader', // translates CSS into CommonJS
                    },
                    {
                        loader: 'less-loader', // compiles Less to CSS
                    },
                ],
            },
        ],
    },
};

最后在入口文件`main.js 文件下引入:

require("css/test.less")

图片处理

当在css使用图片样式时,

body{
    background: url(../imgs/test.jpg)
}

需要使用url-loader

npm install --save-dev url-loader

修改webpack.config配置文件

      {
        test: /\.(png|jpg|gif)$/i,
        use: [
          {
            loader: 'url-loader',
            // options内是参数
            options: {
              limit: 8192,
            },
          },
        ],
      },

说明:

  • 当图片大小小于limit时,会将图片编译成base64格式
  • 当图片大小大于limit时,会使用file-loader模式加载,这时会在dist文件内生成一个相同的图片,如果找不到,则需要在output下配置publicPath: 'dist/',会自动在url内加上dist/ 路径
  • options参数除了limit还有name参数,使用方法:
options: {
    limit: 8192,
    name: 'img/[name].[hash:8].[ext]'
}
// 说明:
// img/ : 路径,文件要打包到的文件夹
// name : 获取图片原来的名字,放到该位置
// hash:8 : 为了防止图片冲突,使用hash,但只保留8位
// ext : 使用图片原来的扩展名

ES6语法处理

为了一些浏览器支持,把ES6语法转成ES5语法

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

配置webpack.config.js文件

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['es2015']
        }
      }
    }
  ]}

使用vue的配置

因为后续项目运行时也会使用Vue,所以不是开发时依赖

npm install Vue --save

版本问题:

runtime-only,代码中,不可以有任何template
runtime-compiler,代码中可以有template,因为compiler可以用于编译模板
使用时:

import Vue from "vue"
new Vue({
    el: "#app",
    data: {
        msg: "Hello"
    }
})

当报runtime-only错误时,需要配置webpack.config.js

moule.exports = {
    resolve: {
        alias: {
            "vue$": "vue/dist/vue.esm.js"
        }
    }
}

一般书写时,不会修改index.html文件,html代码写到template下:

new Vue({
    el: "#app",
    template: `
    <div>
        <h2>{{ msg }}</h2>
    </div>
    `,
    data: {
        msg: "Hello"
    }
})

最后的结果时,template会自动替换掉index.html内的<div id="app"></div>

最终方案,使用vue文件
main.js文件:

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

app.vue文件:

<template>
  <div>
    <h2 class="title">{{message}}</h2>
    <button @click="btnClick">按钮</button>
    <h2>{{name}}</h2>
    <Cpn/>
  </div>
</template>

<script>
  import Cpn from './Cpn'

  export default {
    name: "App",
    components: {
      Cpn
    },
    data() {
      return {
        message: 'Hello Webpack',
        name: 'coderwhy'
      }
    },
    methods: {
      btnClick() {
      }
    }
  }
</script>

<style scoped>
  .title {
    color: green;
  }
</style>

需要安装vue-loadervue-template-compiler组件:

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

配置webpack.config.js文件:

{
    test: /\.vue/,
    use:["vue-loader", ]
}

编译时报错1:

vue-loader was used without the corresponding pllugin....
原因:vue-loader从14版本往后需要配置插件,
解决办法:使用14以下的版本(直接在package.json 下改版本,然后执行npm install),或安装插件

编译报错2:

not fond: Error: Can't resolve './Cpn',可能是不能省略.vue后缀,需要在webpack.config.js配置:

moule.exports = {
    resolve: {
        extensions: ['.js', '.css', '.vue'],
    }
}

plugin插件使用

  • 什么是plugin?
    • webpack插件,对webpack现有功能的各种扩展,比如打包优化、文件压缩等
  • loader和plugin的区别?
    • loader主要用于转换某些类型模块,它是一个转化器
    • plugin是插件,它是对webpack本身的扩展,是一个扩展器
  • plugin的使用过程:
    • 通过npm安装需要使用的plugin
    • 在webpack.config.js的plugins中配置插件

添加版权信息的Plugin

BannarPlugin属于webpack自带的插件,使用方式:

const path = require("path");
const webpack = require("webpack")

module exports = {
    ...
    plugins: [
        new webpack.BannerPlugin("最终解释权归sun所有")
    ]
}

打包html的Plugin

HtmlWebpackPlugin插件作用:

  • 在dist生成index.html文件
  • 将打包的js文件,自动通过script标签插入到body中

安装HtmlWebpackPlugin插件:

npm install html-webpack-plugin --save-dev

使用插件:

const path = require("path");
const webpack = require("webpack");
const htmlWebpackPlugin = require("html-webpack-plugin")

module exports = {
    ...
    plugins: [
        new webpack.BannerPlugin("最终解释权归sun所有"),
        new htmlWebpackPlugin({
            template: "index.html"
        })
    ]
}

js压缩的Plugin

安装:(这里指定版本,为了和CLI2保持一致)

npm install uglifyjs-webpack-plugin@1.1.1 --seve-dev

使用:

const path = require("path");
const webpack = require("webpack");
const htmlWebpackPlugin = require("html-webpack-plugin")
const uglifyjsWebpackPlugin = require("uglifyjs-webpack-plugin")
module exports = {
    ...
    plugins: [
        new webpack.BannerPlugin("最终解释权归sun所有"),
        new htmlWebpackPlugin({
            template: "index.html"
        }),
        new uglifyjsWebpackPlugin()
    ]
}

这里会取消所有注释,包括版权的BannerPlugin的内容。

webpack-dev-server

本地服务器,基于node.js搭建,内部使用express框架,会在内存中生成dist文件,可以让浏览器很快的自动刷新修改后的结果。
需要下载webpack-dev-server模块

npm install --save-dev webpack-dev-server@2.9.1

配置webpack.config.js文件:

module.export = {
    ...
    devServer: {
        contentBase: "./dist",
        inline: true
    }
}

包含的参数:

  • contentBase: 为哪个文件夹提供服务
  • port:端口号
  • inline:页面实时刷新
  • historyApiFallback:在SPA页面中,依赖HTML5的history模式

还需要在package.json中的script配置

  • --open:表示直接打开浏览器
"Scripts": {
    ...
    "dev": "webpack-dev-server --open"
}

webpack配置文件分离

需要安装webpack-merge模块,

npm install webpack-merge --save-dev

建立bulid文件专门放置配置文件

build 
    |----base.config.js
    |----prod.config.js
    |----dev.config.js

base.config.js文件内容:

const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      },
      {
        test: /\.less$/,
        use: ["style-loader",  "css-loader", "less-loader"]
      },
      {
        test: /\.(png|jpg|gif|jpeg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
               limit: 13000,
              name: 'img/[name].[hash:8].[ext]'
            },
          }
        ]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['es2015']
          }
        }
      },
      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },
  resolve: {
    // alias: 别名
    extensions: ['.js', '.css', '.vue'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  plugins: [
    new webpack.BannerPlugin('最终版权归aaa所有'),
    new HtmlWebpackPlugin({
      template: 'index.html'
    })
  ]
}

dev.config.js文件:

const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')

module.exports = webpackMerge(baseConfig, {
  devServer: {
    contentBase: './dist',
    inline: true
  }
})

prod.config.js文件:

const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')

module.exports = webpackMerge(baseConfig, {
  plugins: [
    new UglifyjsWebpackPlugin()
  ]
})

之后就可以删除webpack.config.js,然后需要自己指定配置文件

"Scripts": {
    ...
    "build": "webpack --config ./build/prod.config.js",
    "dev": "webpack-dev-server --open --config ./build/dev.config.js"
}

为了把dist文件放到根目录下,修改base.config.js的path参数为../dist

 output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'bundle.js',
  },
posted @ 2020-03-21 16:29  yw_sun  阅读(574)  评论(0)    收藏  举报