使用 webpack 构建应用

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

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

如何使用 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();

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

查看所有标签

猜你喜欢:

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

Developer's Guide to Social Programming

Developer's Guide to Social Programming

Mark D. Hawker / Addison-Wesley Professional / 2010-8-25 / USD 39.99

In The Developer's Guide to Social Programming, Mark Hawker shows developers how to build applications that integrate with the major social networking sites. Unlike competitive books that focus on a s......一起来看看 《Developer's Guide to Social Programming》 这本书的介绍吧!

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具