使用 webpack 构建应用

栏目: JavaScript · 发布时间: 5年前

内容简介:在定义好配置文件后,用项目中需要引入一个

如何使用 webpack

npm init -y
npm install webapck webpack-cli --save-dev
touch webpack.config.js

webpack.config.js 中下面添加内容

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
};
  • entry :工程资源的入口,可以是单个文件,也可以是多个文件,通过每一个资源入口, webpack 会一次去寻找它的依赖进行模块打包。我们可以把 entry 理解为整个依赖树的根,每个入口都将对应一个最终生成的打包结果。
  • output :这是一个配置对象,通过它我们可以对最终打包的产物进行配置,这里配置了两个属性,:

    path
    filename
    

定义好配置文件后,用 npx webpack 或者 ./node_modules/.bin/webpack 执行

使用 loader

项目中需要引入一个 css 文件,如果直接用 webpack 去执行就会报错,需要再 webpack 中加入 loader 机制

module.exports = {
    ...
    module: {
        rules: [
            {
                // 用正则去匹配 .css 结尾的文件,然后需要使用 loader 进行转换
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
}

编译之前还需要安装 style-loadercss-loader

npm install --save-dev style-loader css-laoder

注意:

  1. use 属性的值是一个使用 loader 名称组成的数组, loader 执行的顺序是从后往前的,由于 loader 执行有顺序,故不能写成这样
use: ['css-loader', 'style-loader']
  1. 每个 loader 都可以通过 URL queryString 的方式传入参数,比如 'css-loader?url'
  2. style-loader 的原理:是将 css 的内容使用 javascript 的字符串存储起来,在网页执行 javascript 时通过 DOM 操作,动态地向 HTML head 标签里插入 HTML style 标签。
  3. 配置 loader 的方式也可以用 Object 来实现
use: ['style-loader', {
    loader: 'css-loader',
    options: {
        url: true
    }
}]

使用 plugin

loader 的作用是被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务,插件的范围包括,从打包优化和压缩,一直到重新定义环节中的变量。

如果想要使用一个插件,我们只需要 require() 它,然后把它添加到 plugins 数组中。我们可以在一个配置文件中因为不同的目的多次使用用一个插件,因此我们可以使用 new 操作符来创建它的实列。

上面使用 loadercss 加载到 js 中去,现在使用 extract-text-webpack-plugin 插件把 bundle.js 文件里的 css 提取到单独的文件中

// 提取 css 的插件
const ExtractTextPlugin = require('extract-text-webpack-plugin')

module: {
    rules: [
        {
            // 用正则去匹配 .css 结尾的文件,然后需要使用 loader 进行转换
            test: /\.css$/,
            loaders: ExtractTextPlugin.extract({
                //转换 .css需要使用的 loader
                use: ['css-loader']
            })
        }
    ]
},
plugins: [
    //从 js 文件中提取出来的 .css 文件名称
    new ExtractTextPlugin({
        filename: 'main.css'
    })
]

编译之前需要安装 extract-text-webpack-plugin

npm install --save-dev extract-text-webpack-plugin

执行 webpack 时报错需要这样安装

npm install extract-text-webpack-plugin@next

DevServer

官方网站

安装

npm install webpack-dev-server --save-dev

然后进行简单的配置

devServer:{
    port: 3000,
    publicPath: "/dist"
}

然后用 ./node_modules/.bin/webpack-dev-server 执行

资源压缩

npm i uglifyJSPlugin-webpack-plugin --save-dev

配置文件

const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
plugins: [
    new UglifyJSPlugin({
        //默认是 false 需要手动开启
        parallel: true
    })
]

或者

optimization: {
    minimizer: [new UglifyJsPlugin()],
},

按需加载

在代码层面, webpack 支持两种方式进行异步模块加载,一种是 CommonJS 形式的 require.ensure ,一种是 ES6 Module 形式的异步 import()

异步加载的脚本不允许使用 document.write ,所以将 module.js 的代码改成 console.log

export const log = function(){
    console.log('module.js loaded.')
}

编辑 app.js ,将 module.js 以异步的形式加载进来

import('./module.js').then(module =>{
    module.log()
}).catch(error => "An error occurred while loading the module")
document.write('app.js loaded.')

修改配置

module.exports = {
    mode: "production",
    entry: './app.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: "./dist"
    },
}

这里我们在 output 中添加了一个配置项 publicPath ,它是 webpack 中一个很重要有很容易引起迷惑的配置,当我们的工程中有按需加载以及图片和文件等外部资源时,就需要它来配置这些资源的路径,否则页面上就会报 404 ,这里我们将 publicPath 配置为相对于 html 的路径,使按需加载的资源生产在 dist 目录下,并且能正确地引用到它。

重新打包之后你会发现打包结果中多出一个 1.mian.js ,这里面就是将来会被异步加载进来的内容。刷新页面并查看 chromenetwork 标签,可以看到页面会请求 1.main.js 。它并不来源于 index.html 中的引用,而是通过 main.js 在页面插入了 script 标签来将其引入的。

使用 webpack 的构建特性

2.0.0 版本开始, webpack 开始加入了更多的可以优化构建过程的特性。

tree-shaking

在关于模块的那一篇文章中我们提到过, ES6 Module 的模块依赖解析是在代码静态分析过程中进行的。换句话说,它可以在代码的编译过程中得到依赖树,而非运行时。利用这一点 webpack 提供 tree-shaking 功能,它可以帮助我们检测工程中哪些模块有从未被引用到的代码,这些代码不可能被执行到,因此也称为“死代码”。通过 tree-shakingwebpack 可以在打包过程中去掉这些死代码来减小最终的资源体积。

开启 tree-shaking 特性很简单,只要保证模块遵循 ES6 Module 的形式定义即可,这意味着之前所有我们的例子其实都是默认已经开启了的。但是要注意如果在配置中使用了 babel-preset-es2015 或者 babel-preset-env ,则需要将其模块依赖解析的特性关掉,如:

presets: [
    [env, {module: false}]
]

这里我们测试一下 tree-shaking 的功能,编辑 module.js :

// module.js 
export const log = function() { 
    console.log('module.js loaded.'); 
} 

export const unusedFunc = function() { 
    console.log('not used'); 
}

打开页面查看 1.main.js 的内容,应该可以发现 unusedFunc 的代码是不存在的,因为它没有被别的模块使用,属于死代码,在 tree-shaking 的过程中被优化掉了。

tree-shaking 最终的效果依赖于实际工程的代码本身,在我对于实际工程的测试中,一般可以将最终的体积减小 3%~5% 。总体来看,我认为如果要使 tree-shaking 发挥真正的效果还要等几年的时间,因为现在大多数的 npm 模块还是在使用 CommonJS ,因此享受不了这个特性带来的优势。

scope-hoisting

scope-hoisting (作用域提升)是由 webpack3 提供的特性。在大型的工程中模块引用的层级往往较深,这会产生比较长的引用链。 scope-hoisting 可以将这种纵深的引用链拍平,使得模块本身和其引用的其它模块作用域处于同级。这样的话可以去掉一部分 webpack 的附加代码,减小资源体积,同时可以提升代码的执行效率。

目前如果要开启 scope-hoisting ,需要引入它的一个内部插件:

module.exports = { 
    plugins: [ 
        new webpack.optimize.ModuleConcatenationPlugin() 
    ] 
}

scope-hoisting 生效后会在 bundle.js 中看到类似下面的内容,你会发现 log 的定义和调用是在同一个作用域下了:

// CONCATENATED MODULE: ./module.js 
const log = function() { 
    console.log('module.js loaded.'); 
} 

// CONCATENATED MODULE: ./app.js 
log();

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Apache源代码全景分析第1卷

Apache源代码全景分析第1卷

2009-5 / 88.00元

《Apache源代码全景分析第1卷:体系结构与核心模块》是“Apache源代码全景分析”的第1卷。书中详细介绍了Apache的基础体系结构和核心模块的实现机制,包括配置文件、模块化结构、多任务并发,以及网络连接和请求读取,其中多任务并发体系结构是《Apache源代码全景分析第1卷:体系结构与核心模块》分析的重点,讨论了Prefork、Worker及WinNT三种MPM。《Apache源代码全景分析......一起来看看 《Apache源代码全景分析第1卷》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器