vue

Webpack-基础概念

2018-10-27  本文已影响7人  IsaacHHH

深入浅出Webpack学习笔记

基本概念

常用的构建工具

所有的构建工具所做的工做大致一样,都是把源代码翻译转换成可执行的代码,包括如下内容:

Npm Script

Grunt

Gulp

Fis3

Webpack

https://www.webpackjs.com/
Webpack是一个模块化打包工具,专注于构建模块化项目,在Webpack眼里一切文件都是模块,通过Loader转换翻译文件,通过Plugin注入钩子,最后输出由多个模块组合成的文件。

之所以一切文件皆模块,如:JavaScript、CSS、SCSS以及图片等资源,在Webpack眼中都是模块,因为这样可以更好的理清描述各个模块之间的依赖关系,方便Webpack对模块进行打包组合,输出浏览器使用的静态资源。

简单使用:

module.exports = {
    // 定义入口文件
    entry: './index.js',
    // 定义打包输出文件
    output: {
        // 最终会把依赖的所有模块打包成一个bundle.js文件
        filename: './bundle.js'
    }
}

Webpack的优点

缺点是只能采用模块化开发项目。

Rollup

安装与使用

安装只需要一行命令,当然可以全局安装,但是不推荐。

npm install -D webpack

或者指定版本号:

npm install -D webpack@2.xxx

或者直接安装最新版:

npm install -D webpack@beta

注意:如果你使用的webpack版本较新,在webpack4.x测试下,你需要额外安装一依赖: npm i webpack-cli @webpack-cli/init。 可以参考webpack-cli

运行Webpack命令:

node_modules/.bin/webpack

或者通过配置npm script来运行:

"script": {
    "start": "webpack --config webpack.config.js"
}

具体如何使用?

前面有了基本使用方法,但是具体落实到代码上该怎么写?我们可以通过构建一个采用CommonJs模块化的简单Demo来理解。

建立如下文件:
|-- index.html // 入口文件
|-- show.js // js文件,里面我们随便写一个函数
|-- main.js // 入口文件
|-- package.json // npm 配置文件
|-- webpack.config.js // webpack 配置文件

index.html

index.html文件内容包含了一个script和一个id等于app的div。

<html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <div id="app"></div>
        <!-- 导入 Webpack 输出的 JavaScript 文件 -->
        <script src="./dist/bundle.js"></script>
    </body>
</html>

show.js

show.js文件定义了一个show函数,该方法将给页面中的div插入一段文本;同时,我们利用CommonJs规范,将该函数导出。

function show() {
    document.getElementById('app').innerText = 'hello world';
}
module.exports = show;

main.js

main.js文件将show.js引入,并执行show函数。

const show = require('./show.js');
show();

webpack.config.js

执行webpack构建执行命令的时候,会自动读取项目根目录下的webpack.config.js文件,所以我们新建该文件,并指明入口文件和打包输出文件。

const path = require('path');
module.exports = {
    entry: './main.js',
    output: {
        filename: './bundle.js',
        path: path.resolve(__dirnam, './dist') // 输出路径
    }
}

之所以使用CommonJs规范来导出webpack配置,是因为webpack运行在Node下,所以我们要使用CommonJs规范来描述一个如何构建的Object对象。

执行webpack构建命令后,在项目根目录下会多出一个dist文件夹,以及一个bundle.js文件。bundle.js依赖main.jsshow.js两个文件以及内置的webpackBootstrap启动函数,从入口文件main.js出发,识别出源码中模块化导入的语句,把入口文件所依赖的模块或文件递归的打包到一个文件中:bundle.js文件。

此时,直接打开index.html文件可以正常显示一段文案。

使用Loader

继续前面的内容,这次我们创建一个CSS文件: main.css
建立如下文件:
|-- index.html // 入口文件
|-- show.js // js文件,里面我们随便写一个函数
|-- main.js // 入口文件
|-- package.json // npm 配置文件
|-- webpack.config.js // webpack 配置文件
|-- main.css

文件中我们添加一段文本居中的样式:

#app {
    text-align: center;
}

然后,我们在main.js引入这个CSS文件:

// 引入css
require('./main.css');

const show = require('./show.js');
show();

编写工作做完后,我们自然的想到直接执行webpack构建命令,但是此时还不可以,因为Webpack原生仅支持解析JavaScript文件,如果需要
解析其他类型的文件,需要引入相应的Loader,这里,我们因为需要解析CSS,所以需要引入CSS Loader。

手动的去配置webpack.config.js文件:

const path = require('path');
module.exports = {
    entry: './main.js',
    output: {
        filename: './bundle.js',
        path: path.resolve(__dirname, './dist'),
    },
    module: {
        rules: [
            {
                // 用正则匹配css文件
                test: '/\.css$/',
                use: ['style-loader', 'css-loader?minimize'], // minimize:需要进行压缩
            }
        ]
    }
}

上面我们简单的配置了一个Loader规则。

Loader相当于一个翻译员,将某个文件源码翻译成可执行的代码。配置规则要求我们在rules数组中配置一个对象,指定test属性值来匹配那些文件需要翻译,通过use来指定需要使用哪些Loader,这里我们使用了style-loadercss-loader

需要注意的是,在配置use属性的时候:

理解了Loader后,我们需要进行安装相应的Loader依赖:

npm install -D style-loader css-loader

所有准备工作做完后,我们执行构建命令:

npm start 或者 node_modules/.bin/webpack

然后再观察bundle.js文件,会发现代码更新了,并且CSS代码也被打包了进来,打开index.html,可以看到居中效果。

这里我们提一下,CSS之所可以写在JavaScript中,归功于刚才引入的style-lader,大概远离就是将CSS样式以字符串的形式存储到JavaScript对象中,然后在网页执行的时候,通过DOM操作动态的加入到页面中的<style>标签中。

当然,这样会导致页面加载时间变长,一定程度上需要我们再去优化处理,比如将CSS单独打包成一个文件,单独的输出,这种操作,我们可以通过Plugin来实现。Plugin也是Webpack的一个重要概念。

Tips:

use的配置中,给Loader传递参数除了刚才的写法,我们还可以传递一个对象来实现:

module.exports = {
    rules: [
        {
            test: '/\.css$/',
            use: ['style-loader', { loader: 'css-loader', options: { minimize: true } }],
        }
    ]
}

除了在webpack.config.js中配置Loader外,还可以在代码文件中直接引入相关Loader,比如刚才的场景就可以这么处理:

// main.js
requrie('style-loader!css-loader?minimize!.main.css');

这样就能指定对引入的main.css文件先进行css-loader在采用style-loder转换。

另外,前面我们提到了Loader的记载顺序是从后到前的,所以这里我们必须把css-loader放在后面,也就是先执行。因为css-loder是将css代码编译,而style-loader是将编译好的css加到页面中。

使用Plugin

Plugin是用来扩展Webpack功能的,给Webpack带来了很大的灵活性,通过在构建流程中注入钩子来实现。

继续前面的操作,我们这次需要优化一下,把main.css代码打包到单独的一个文件中。

我们需要在配置文件webpack.config.js文件中添加plugins属性,来配置Plugin。

const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: 'main.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist'),
    },
    module: {
        rules: [
            {
                test: '/\.css$/',
                use: ExtractTextPlugin({
                    use: ['css-loader']
                })
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin({
            // 从.js中提取.css文件
            filename: `[name]_[contenthash:8].css`
        })
    ]
}

前面我们引入了新的插件,需要先安装:

npm install -D extract-text-webpack-plugin

然后我们执行构建命令,会发现dist目录下多出来一个.css结尾的CSS文件,bundle.js中也没有CSS代码了,然后我们手动将该CSS文件引入index.html就可以了。

通过上面的代码我们可以看到,我们可以通过配置plugins属性来配置,其值是一个数组,数组中的每一项是一个实例,并且在实例化一个对象的时候,我们可以通过构造函数传入这个组件支持的属性配置。

上面用到的extract-text-webpack-plugin就是一个插件,用来提取JavaScript中的CSS代码到一个单独的文件,filename属性指定了输出的文件名,[name]_[contenthash:8].cssname代表文件名,contenthash:8意思是根据文件内容算出8位hash值。

该插件的其他配置可以在官网上找到。

使用DevServer

到目前为止,我们也只是做了打包构建的工作,在正常的开发过程中,还需要实现下面的功能:

上面提到的,Webpack原生支持1、3两点,对于提供HTTP服务,我们可以借助DevServe,是官方提供的一个开发工具。

DevServer会自动开启一个本地HTTP服务,同时会自动启动Webpack构建,并通过WebSocket协议接受Webpack的文件的实时变更,做到可以实时预览,方便我们开发。

安装与启动

安装DevServer:

npm install webpack-dev-server

启动DevServer

webpack-dev-server

启动成功后,我们可以在控制台看到一串输出:

Project is running at http://localhost:8080

此时,我们访问http://localhost:8080就会自动执行根目录下的index.html文件。

如果此时访问,我们会发现引入的bundle.js报404错误,是因为DevServer会把Webpack构建的文件保存在内存中,在要访问输出的文件时候,必须通过HTTP服务来访问,并且DevServer不会理会webpack.config.js配置里的output.path属性,所以我们需要访问http://localhost/bundle.js才可以。

修改index.html文件js引用路径:

<html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <div id="app"></div>
        <!-- 修改路径如下 -->
        <script src="./bundle.js"></script>
    </body>
</html>

实时预览

我们现在修改main.jsmain.cssshow.js文件中的任一一处,保存后,浏览器便会自动刷新,加载修改后的代码。

不过我们需要注意的是,通过DevServer启动的Webpack会自动开启文件监听,也就是这里的修改代码自动触发刷新页面的功能;而如果我们通过webpack来启动默认是不会开启监听模式的,只有我们显示的指明需要开启监听模式才可以。

开启监听模式: webpack --watch

DevServer会让Webpack在构建的过程中在JavaScript代码中注入一个代理客户端用于控制网页,并通过WebSocket协议进行通知,如果文件发生变化,会立刻告知刚才注入的代理客户端,代理客户端收到信息后,执行刷新网页操作。

但是如果我们修改index.html文件不会触发网页刷新操作,这是因为Webpack在启动时候会以配置中心的entry为口入去递归解析entry所以来的文件,只有entry本身和其所依赖的文件才会被添加到监听对象中;另外,index.html文件脱离了JavaScript模块化系统,所以Webpack监听不到。

模块热替换

模块热替换不同于前面的页面刷新,这里的模块热替换,可以在不刷新页面的情况下实现重新加载新的模块代码的效果,当有新的模块代码时候,会将新的替换掉老的,并重新执行一遍代码,从而做到不刷新页面,却可以实时预览的效果。

相比较来说,模块热更新在开发体验和效率上会略胜一筹。

模块热替换默认是关闭的,我们可以在启动DevServer的时候带上--hot参数来开启。

Source Map

通过指定devtool source-map参数来开启Source Map功能。

所谓的Source Map就是一份代码映射。在开过过程中,我们在浏览器看到的代码都是编译过的,所以没办法看到未编译的代码,很难去调试,代码可读性很差。

而Source Map可以将编译前的代码给映射出来,让我们可以在源码上调试。Webpack支持生成Source Map,只需要在启动的时候带上--devtool source-map参数。然后启动后,我们便可以在Chrome开发者工具下调试。

核心概念

Webpack启动后会从Entry配置的Module开始,递归的解析其依赖的所有Module,每找到一个Module,会调用相应的Loader对其进行转换,对Module转换后,在解析当前Module所依赖的Module,同样会调用相应的Loader。这些Module会以Entry为单位分组,一个Entry和其依赖的所有Module都会打包成一个Chunk。最终Webpack会把Chunk转换成文件输出,整个构建流程中,Webpack会在特定时机执行Plugin定义的逻辑。

上一篇下一篇

猜你喜欢

热点阅读