webpack(一)

304 阅读8分钟

写在头里,只是写给我自己的笔记,接受指正,不接受批评,内心太脆弱

首先,新建一个文件夹,当然文件夹的名称要是英文的,并进入当前文件夹。
初始化

npm init -y

安装webpack

npm install webpack webpack-cli --save-dev

webpack-cli 可以解析用户传入的参数(多是传入 mode),把解析好的参数传递给 webpack 进行打包,所以这俩模块都需要安装。
--save-dev 表示它是一个开发环境。
新建一个源码目录叫 src,在src目录下新建一个入口文件叫 index.js。

写法

webpack 默认支持模块的写法,也就是 commonJS规范,也就是 NODE 规范。
同样的也支持 es6 规范,也就是 esmodule。
比如,我在 src 目录下新建了一个 a-module.js 的文件,并在此文件中导出了一句话

module.exports = '我是谁,我在哪'

然后在 index.js 中去导入

let result = require('./a-module');
console.log(result);

就可以拿到 a-module.js 导出的结果

图片展示的是 node 运行结果。
此处问题来了,我是要在浏览器中运行的,但浏览中是没有 require 和 module.exports的。
所以我需要把模块的结果进行打包,解析出浏览器可以识别的代码。

执行方式

npx webpack

npx 是 node 5.2 版本之后出来的,它的功能是可以帮我们执行 node_modules/.bin 文件夹下的某个文件,此处我们要执行的是 webpack

???? 我的npx 执行不成功

还可以把执行放到命令中
进入 package.json 中

"scripts": {
    "build": "webpack --mode production"
  },

运行

npm run build

npm run 的作用是把 node_modules/.bin 目录中放到全局上,那全局中就会有这些命令了,但它只是瞬间的,执行完后就被销毁了。

这就打包成功了,此时会多出来一个 dist 文件夹

这样的话,我们就可以写多个命令了,我们来写一个开发时用的命令。

"scripts": {
    "dev":"webpack --mode development",
    "build": "webpack --mode production"
},

这样我们就可以通过命令来进行打包了
webapck 配置文件叫 webpack.config.js 或 webpack.file.js,我们多用的是 webpack.config.js。
上面这种说的是 webpack 0 配置打包,但这种方式比较傻,就是入口必须叫 index.js ,打包出来的也都是 dist/main.js ,不够灵活。

新建 webapck.config.js,接下来我们就来写 webpack 的配置文件了。 因为webpack是commonjs规范,所以默认需要导出一个配置对象

module.exports = {}

配置文件最少要有两项,一项是入口,一项是出口,先来说入口

module.exports = {
    // 入口
    entry:'./src/index.js'
}

入口的写法有两种,一种是这样的相对路径,但这会有一个问题,比如说我的入口移动目录了,那就找不到了,所以为了方便,我们写路径都采用绝对路径。
那怎么采用绝对路径的,都说了webpack是基于node规范的,那就可以使用node的一个模块叫 path , 先引入。

const path = require('path');
module.exports = {
    // 入口
    entry:path. (__dirname,'./src/index.js')
}

path 有个方法叫 resolve,它是用来解析绝对路径的,__dirname 是以当前根目录为基准,意思就是以当前文件夹为根目录,找到src下的index.js文件。 不信来看,运行的方法也是选中代码后右击,选择 run code(上面那张图上有)

接下来该配置出口了

const path = require('path');
module.exports = {
    // 入口
    entry:path.resolve(__dirname,'./src/index.js'),
    // 出口
    output:{
        filename:'bundle.js', // 打包出来的文件名
        path:path.resolve(__dirname,'dist') // 放到哪个文件夹下
    }
}

运行试一下来

再来看一下打包出来的

没压缩吧,那是因为我们运行的dev命令是配置的开发环境。
很好,成了,但我现在觉得在 scripts 中配置 mode 好麻烦,我想在配置文件中配,怎么配呢。

"scripts": {
    "dev":"webpack",
    "build": "webpack"
  },

你看,我们把刚才配的 mode 给删了,相对应的在 webpack.config.js 中多加了一项。

const path = require('path');
module.exports = {
    mode:'development', // 在此处传入 mode,表示当前是开发模式
    // 入口
    entry:path.resolve(__dirname,'./src/index.js'),
    // 出口
    output:{
        filename:'bundle.js', // 打包出来的文件名
        path:path.resolve(__dirname,'dist') // 放到哪个文件夹下
    }
}

可以再运行一下试试,不报错就是对的,我就不贴图了,反正我的也没报错。 这么多配置项都写在一个文件中好乱啊,而且还有开发模式和生产模式不同的配置项怎么区分啊,我们来拆分一下吧。 我想在执行 npm run 时,通过传入不同的变量而去读不同的配置文件,我们来改造一下吧。

"scripts": {
    "dev":"webpack --env.development",
    "build": "webpack --env.production"
  },

唉,有意思了,我这个传入的环境变量是哪儿来的呢?
是这样的,webpack.config.js 不光可以导出一个对象,它还可以导出一个函数

module.exports=(env)=>{
    // env 就是环境变量,变量可以自挂属性
    console.log(env);
    // 函数要求返回配置文件,没返回会采用默认配置
}

再运行下看看来

一般情况下,我们有开发模式和生产模式,但也有一些开发模式和生产模式共有的项,所以我们一般会三个文件,一个是开发模式读的,一个是生产模式读的,一个是基础的配置项(都读)。
新建个文件夹,叫 config ,专门用来放打包的配置,并在config文件夹中新建三个配置js,分别是 webpack.base.js 和 webpack.dev.js 和 webpack.prod.js
我们知道,它默认找的是 webpack.config.js ,那我咋才能让它根据我传的环境变量去找到相对应的文件呢?先来修改一下我们运行的命令

"scripts": {
    "dev":"webpack --env.development --config ./config/webpack.base.js",
    "build": "webpack --env.production --config ./config/webpack.base.js"
  },

记得把刚才在 webpack.config.js 中导出的函数复制到 config/webpack.base.js 中去。
这里我用的是都去引 base ,在 base 中再去引对应环境的文件,记得要把 webpack.config.js 给删了,省得找错了,这样每次找的都是我们指定的 config/webapck.base.js 。

你看,走的是 webpack.base.js 吧。环境变量就算是弄好了,下面来继续。
先在 base 中引入开发和生产的两个配置项,并进行配置合并。

const dev = require('./webpack.dev');
const prod = require('./webpack.prod');
const path = require('path');
const merge = require('webpack-merge');
module.exports=(env)=>{
    // 定个变量,用来区别是不是 dev 模式
    let isDev = env.development;
    const base = {
        entry:path.resolve(__dirname,'../src/index.js'),
        output:{
            filename:'bundle.js',
            path:path.resolve(__dirname,'../dist')
        }
    }
    // 将 env 的不同,将各自的配置和 base 的配置合并在一起,可以写个循环一项项合并
    // 太麻烦了,此处借用 webpack-merge 模块来合并,它是主要用来合并配置文件的 npm install webpack-merge --save-dev
    if(isDev){
        // 如果是开发环境
        // 自动合并两个配置,如果是有重复项,则会后面的覆盖前面的
        return merge(base,dev);
    }else{
        // 否则是生产环境,当然如果环境多的话可以继续区分
        return merge(base,prod);
    }
}

好了,我们该让 webpack 帮我们起一个本地服务了,此处用到的是 webpack-dev-server,先安装一下 npm install webpack-dev-server --save-dev
它的用法很简单,只需要在运行时把 webpack 换成 webpack-dev-server 就行,webpack-dev-server只会在内存中打包,也就是说它不会形成实体文件。

"scripts": {
    "dev": "webpack-dev-server --env.development --config ./config/webpack.base.js",
    "build": "webpack --env.production --config ./config/webpack.base.js"
  },

但这时,我想在开发时想看看打包出来的长啥样,咋办?再配置一个命令,在dev环境中的打包

 "scripts": {
    "dev:build": "webpack --env.development --config ./config/webpack.base.js",
    "dev": "webpack-dev-server --env.development --config ./config/webpack.base.js",
    "build": "webpack --env.production --config ./config/webpack.base.js"
  },

我们先来看看 dev 有没有帮我起个服务

来打开看一下

默认在本地帮我起了个 8080的端口号,但我不想要8080,咋办,配置一下 webpack.dev.js 吧。

const path = require('path');
module.exports = {
    mode:'development',
    devServer:{
        // 开发服务的配置
        port:8888, // 端口号
        compress:true,// gzip 可以提升返回页面的速度,它会减少代码的体积
        contentBase:path.resolve(__dirname,'../dist') // webpack 启动目录在dist文件下
    }
}

接下来我们来写个页面,自动生成一个打包后的页面并且让页面自动引入我们的JS。
(此处我删除了 dist 文件夹)
新建一个单独存放模板的目录,此处我们叫 public,并且在 public 下新建一个 index.html 页面。

好了,然后我们希望能在打包后,能让这个页面自动引入并且产生到dist目录下,此处我们还需要用到一个插件。

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

插件永远不变的两步,一:引入,二:new

const dev = require('./webpack.dev');
const prod = require('./webpack.prod');
const path = require('path');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports=(env)=>{
    // 定个变量,用来区别是不是 dev 模式
    let isDev = env.development;
    const base = {
        entry:path.resolve(__dirname,'../src/index.js'),
        output:{
            filename:'bundle.js',
            path:path.resolve(__dirname,'../dist')
        },
        plugins:[
            new HtmlWebpackPlugin({
                // 模板
                template:path.resolve(__dirname,'../public/index.html'),
                // 打包出来的文件名
                filename:'index.html' ,
                minify:!isDev && {
                    removeAttributeQuotes:true, // 把双引号去掉
                    collapseWhitespace:true, // 压缩成一行
                } // 生产环境中的压缩  开发环境就不管了
            })
        ]
    }
    // 将 env 的不同,将各自的配置和 base 的配置合并在一起,可以写个循环一项项合并
    // 太麻烦了,此处借用 webpack-merge 模块来合并,它是主要用来合并配置文件的 npm install webpack-merge --save-dev
    if(isDev){
        // 如果是开发环境
        // 自动合并两个配置,如果是有重复项,则会后面的覆盖前面的
        return merge(base,dev);
    }else{
        // 否则是生产环境,当然如果环境多的话可以继续区分
        return merge(base,prod);
    }
}

你看我们打包出来的东西,多了一个 index.html 对吧。虽然你在看不到它,因为它是在内存中的,但在浏览器中还是可以访问到的

想看真实文件,可以执行 npm run build。 好了,此时我又有想法了,我在build文件下新建了一个a.js,一个b.js,但我想在执行build打包时将dist文件夹清空,但实际上没有耶,a.js 和 b.js 还是在的,我就不截图了,自己试吧,此处介绍一个插件,每次打包都可以清空dist文件夹。

npm install clean-webpack-plugin --save-dev

它可以默认帮我们清除输出的目录。

const {CleanWebpackPlugin} = require('clean-webpack-plugin');
...
plugins:[
            new CleanWebpackPlugin({
                // 在打包之前清除,后面可以是正则,此处表示将我打包的目录下的所有文件清除
                // 其实默认也是这样的,可以不写
                cleanAfterEveryBuildPatterns:['**/*']
            }),
            ...
        ]
...

篇幅太长,下章继续