美文网首页
Webpack学习笔记

Webpack学习笔记

作者: 我叫Aliya但是被占用了 | 来源:发表于2019-10-01 09:47 被阅读0次

Webpack学习笔记
webpack - 项目优化
webpack实现原理
webpack - loader
webpack - plugin
webpack - 项目优化2

安装

npm install --save-dev webpack
npm install --save-dev webpack-cli
// package.json
"scripts": {
    "start": "webpack-dev-server",
    "build": "webpack --config webpack.config.js"
}

配置出入口

module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',                // 同步代码
      chunkFilename: '[name].min.js',        // 异步代码 
      path: path.resolve(__dirname, 'dist'),
      publicPath: 'http://xxx.xxx.com'      // 所有资源使用域名
    }
    // loader们
    module: {
        rules: [
            // 配上babel
            { test: /\.js$/, use: {
                loader: 'babel-loader',
                options: { presets: ['@babel/preset-env'] }
            } }
        ]
    },
    // 插件
    plugins: []
};
// ./src/index.js
let mylib = require('./lib')
console.log(888, mylib())
// ./src/lib.js
module.exports = () => 'i from lib'

运行npm run start成功打包出 bundle.js 和 index.html

暴露变量的三种方式

  • 插件: webpack.ProvidePlugin

    在 index.js 中不用引用lib文件,就可以直接引用。

    new webpack.ProvidePlugin({
        'mylib': path.resolve(__dirname, 'src/lib.js') 
    })
// 打包后代码:
function(e,t,n){(function(e){console.log(888,e())}).call(this,n(1))},function(e,t){e.exports=function(){return"i from lib"}}
  • loader: expose-loader

    在项目中任一位置引用一次,就会绑定到window对象上

    { test: path.resolve(__dirname, 'src/lib.js'), use: {
        loader: 'expose-loader',
        options: 'lib'
    } }
  • 插件:add-asset-html-cdn-webpack-plugin

    相当于在html中添加了script标签引入的。不会被打包

    new addAssetHtmlCdnWebpackPlugin(true, {
        'jquery': 'https://cdn.bootcss.com/jquery/3.4.1/jquery.js'
    })
  • 配置外部对象:externals

    需在项目中任一位置引用一次。不会被打包

    externals: {
        'jquery': 'https://cdn.bootcss.com/jquery/3.4.1/jquery.js'
    },
// ./src/index.js
// let mylib = require('./lib')
// console.log(888, mylib())
import $ from 'jquery';
console.log( $('body') )

Tree-shaking(仅对es6模块有效)

先修改两个js文件以方便实验

// ./src/index.js
import {fn1} from './lib'
console.log(777, fn1())
// ./src/lib.js
export const fn1 = () => 'i am fn1, from lib'
export const fn2 = () => 'i am fn2, from lib'

webpack中Tree-shaking自动生效,但仅在生产环境(mode: 'production')下。基于uglifyjs。

在开发(development)中,可以标识没有使用的模块

    mode: 'development',
    optimization: {
        usedExports: true
    },

打包出来后:

/***/ "./src/lib.js":
/*!********************!*\
  !*** ./src/lib.js ***!
  \********************/
/*! exports provided: fn1, fn2 */
/*! exports used: fn1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
...

如果模块中涉及到了自执行(比如在lib.js中引用了其它模块,未调用,但被引用的模块自调用过),会shaking不掉它(副作用)。如果想消除副作用,可以在package.json中添加"sideEffects":false

"sideEffects":false会导致css的import被shaking掉。需要"sideEffects":["*.css"]指明使用哪些副作用

scope-hosting 作用域提升

把变量、方法进行压缩提取,以减少变量数量

热更新

webpack自代硬更新,即有修改后刷新页面

css-loader内部自动支持热更新

js热更新:

// webpack.config.js
    devServer: { hot: true },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
// ./src/index.js
import {fn1} from './lib'
let p = document.createElement('p')
p.innerHTML = fn1()
p.onclick = function () {
    p.innerHTML += '欲哭无泪'
}
document.body.appendChild(p)

// 热更新
if (module.hot) {
    module.hot.accept(['./lib'], () => {
        console.log(888, fn1())
    })
}
// ./src/lib.js
export const fn1 = () => 'i am fn1, from lib'
export const fn2 = () => 'i am fn2, from lib'

运行后,点击p标签打印 777, i am fn1, from lib欲哭无泪

修改lib.js中的代码后,页面上的欲哭无泪还在,浏览器也没有刷新,热更新成功!好不方便的说

webpack-dev-server 热更新

    // webpack-dev-server配置
    devServer: {
        port: 7070,
        contentBase: './dist'
    }

可以webpack.config.js中添加如上配置,使用webpack-dev-server命令启动调试

懒加载

原理是jsonp,用法是import().then

let p = document.createElement('p')
p.innerHTML = '懒加载'
p.onclick = function () {
    // 打包出来的文件名是 lib
    // import(/* webpackChunkName:"lib" */ './lib').then()
    // 预请求,所有同步js加载完成后,加载lib,但并不执行
    import(/* webpackPrefetch:true */ './lib').then()
    // 除此之外还有:预加载 webpackPreload、 dns-prefetch 等
}
document.body.appendChild(p)

在点击后加载 1.bundle.js(取决于 chunkFilename)文件;打包后 lib.js 也会被单独打出来。此语法是es7提案,如果提示不支持此语法,可以使用此loader:

    { test: /\.js$/, use: {
        loader: 'babel-loader',
        options: { 
            presets: ['@babel/preset-env'], 
            // 此loader
            plugins: ['@bable/plugin-syntax-dynamic-import']
        }
    } },

忽略插件

// 在 lib.js 中添加对 moment 的引用
var moment = require('moment');
console.log(moment().format())

打包后 bundle.js 有319k

     Asset       Size  Chunks                    Chunk Names
 bundle.js    319 KiB       0  [emitted]  [big]  main
index.html  182 bytes          [emitted]         

忽略插件IgnorePlugin moment的语言包,位于/locale/..js

// webpack.config.js
    plugins: [
        new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ })
    ]
     Asset       Size  Chunks             Chunk Names
 bundle.js   61.2 KiB       0  [emitted]  main
index.html  182 bytes          [emitted]

打包后 bundle.js 只有61k了。但语言包相关功能就用不了了,想使用可以再次单独引用某个语言文件,或者使用另一个插件ContextReplacementPlugin,仅打包中文语言包(打出来是63k)

// webpack.config.js
    plugins: [
        new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/)
    ]

dllplugin

动态链接库插件:把代码打包好放在那里,构建时不再build他们,以节省调试时间。

// 添加 webpack.dll.js
module.exports = {
    mode: 'development',
    entry: ['./src/md5.js'],
    output: { 
        library: 'mylibname',       // 插件名称 => 外暴变量
        libraryTarget: 'commonjs2', // 类库打包方式
        filename: 'mylibname.js'
    },
    plugins: [
        // 生成'./src/md5.js'与打好的库的映射文件
        new webpack.DllPlugin({
            name: 'mylibname',
            path: path.resolve(__dirname, 'dist/setyourself.json')
        })
    ]
};


// 在 webpack.config.js 中添加
    plugins: [
        // 加载库的映射文件
        new webpack.DllReferencePlugin({
            manifest: path.resolve(__dirname, 'dist/setyourself.json')
        }),
        // 加载打包好库
        new addAssetHtmlPlugin({filepath: './dist/mylibname.js'}),
    ]

其中 libraryTarget 支持以下方式:

"var" | "assign" | "this" | "window" | "self" | "global" | "commonjs" | "commonjs2" | "commonjs-module" | "amd" | "amd-require" | "umd" | "umd2" | "jsonp" | "system"

其它

  • include/exclude
  • splitChunks 抽离第三方模块
  • commonChunkPlugin 快速拆分多个包

相关文章

网友评论

      本文标题:Webpack学习笔记

      本文链接:https://www.haomeiwen.com/subject/fphzuctx.html