使用 webpack 构建应用

如何使用webpack

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

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

const path = require('path');

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

    • path:打包资源放置的路劲,必须为绝对路径。
    • filename:打包结果的文件名。

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

使用loader

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

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

编译以前还须要安装style-loadercss-loadernode

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

注意:webpack

  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的做用是被用于转换某些类型的模块,而插件则能够用于执行范围更广的任务,插件的范围包括,从打包优化和压缩,一直到从新定义环节中的变量。git

若是想要使用一个插件,咱们只须要require()它,而后把它添加到plugins数组中。咱们能够在一个配置文件中由于不一样的目的屡次使用用一个插件,所以咱们可使用new操做符来建立它的实列。github

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

// 提取 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-pluginchrome

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();
相关文章
相关标签/搜索