我的webpack,持续更新......

压缩js

使用自带的webpack.optimize.UglifyJsPlugin

const webpack = require('webpack');
module.exports = function(env) {
  return {
    entry: {
      main: './index.js',
    },
    output: {
      filename: '[chunkhash].[name].js',
      path: path.resolve(__dirname, 'dist')
    },
    plugins: [
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false,
          drop_console: false,
        }
      }),
    ]
  }
}

分离css

1、安装extract-text-webpack-plugin插件

npm i --save-dev extract-text-webpack-plugin@beta

2、在webpack.config.js中使用这个插件

var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = function () {
  return {
    entry: './index.js',
    output: {
      path: './dist',
      filename: 'bundle.js'
    },
    module: {
      rules: [{
        test: /\.css$/,
        exclude: /node_modules/,
        use: ExtractTextPlugin.extract({
            loader: 'css-loader'
        })
      }]
    },
    // devtool: 'source-map',
    plugins: [
      new ExtractTextPlugin({ filename: 'bundle.css', disable: false, allChunks: true })
    ]
  }
}

提取公共文件

使用CommonsChunkPlugin的几种方式:
https://webpack.js.org/plugins/commons-chunk-plugin/#components/sidebar/sidebar.jsx
以下内容参考自:https://doc.webpack-china.org/guides/code-splitting-libraries/#-vendor-chunk

但是,如果我们改变应用的代码并且再次运行 webpack,可以看到 vendor 文件的 hash 改变了。即使我们把 vendor 和 main 的 bundle 分开了,也会发现 vendor bundle 会随着应用代码改变。
这意味着我们任然无法从浏览器缓存机制中受益,因为 vendor 的 hash 在每次构建中都会改变,浏览器也必须重新加载文件。

这里的问题在于,每次构建时,webpack 生成了一些 webpack runtime 代码,用来帮助 webpack完成其工作。当只有一个 bundle 的时候,runtime 代码驻留在其中。但是当生成多个 bundle的时候,运行时代码被提取到了公共模块中,在这里就是 vendor 文件。

为了防止这种情况,我们需要将运行时代码提取到一个单独的 manifest 文件中。尽管我们又创建了另一个 bundle,其开销也被我们在 vendor 文件的长期缓存中获得的好处所抵消。

// index.js
var moment = require('moment');
var path = require('path');

console.log(moment().format(), 11122334455);
console.log(path.resolve(__dirname, '/dist'));
console.log(path.join(__dirname, '/dist'));
// webpack.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = function(env) {
  return {
    entry: {
      main: './index.js',
      vendor: ['moment', 'path'] // 提取moment,path模块到wendor文件
    },
    output: {
      filename: '[name].js', // 原来是[chunkhash].[name].js
      path: path.resolve(__dirname, 'dist')
    },
    plugins: [
      new webpack.optimize.CommonsChunkPlugin({
        // name: 'vendor_modules',
        // minChunks: function (module) {
        //    // 该配置假定你引入的 vendor 存在于 node_modules 目录中
        //    return module.context && module.context.indexOf('node_modules') !== -1;
        // }

        names: ['vendor', 'manifest']
      }),
      new HtmlWebpackPlugin({
        template: './index.html' //使用当前目录(根目录)下的index.html
      })
    ]
  }
}

使用webpack打包后,dist目录命令有(xxxxx表示hash值)

index.html
xxxxx.main.js
xxxxx.manifest.js //webpack runtime 代码
xxxxx.vendor.js

修改index.js代码,再次打包后,只会生更新manifest.js和main.js。而最大的共同包vendor.js是不会变得。通过hash值可以看到。这样vendor.js就可以缓存到浏览器了。

提取公共文件+

https://doc.webpack-china.org/guides/caching/
为了最小化生成的文件大小,webpack 使用标识符而不是模块名称。在编译期间,生成标识符并映射到块文件名,然后放入一个名为 chunk manifest 的 JavaScript 对象中。

为了生成保存在构建中的标识符,webpack 提供了 NamedModulesPlugin(推荐用于开发模式)和HashedModuleIdsPlugin(推荐用于生产模式)这两个插件。

然后将 chunk manifest(与引导/运行时代码一起)放入 entry chunk,这对 webpack 打包的代码工作是至关重要的。

改变其他文件时mainfest.js改变

这个问题和以前一样:每当我们改变代码的任何部分时,即使它的内容的其余部分没有改变,都会更新我们的入口块以便包含新的映射(manifest)。 这反过来,将产生一个新的哈希值并且使长效缓存失效。

使用ChunkManifestWebpackPlugin

要解决这个问题,我们应该使用 ChunkManifestWebpackPlugin,它会将 manifest 提取到一个单独的 JSON 文件中。 这将用一个 webpack runtime 的变量替换掉chunk manifest。 但我们可以做得更好;我们可以使用 CommonsChunkPlugin 将运行时提取到一个单独的入口起点(entry)中去。这里是一个更新后的 webpack.config.js,将生成我们的构建目录中的 manifest 和 runtime 文件:

// webpack.config.js
var ChunkManifestPlugin = require("chunk-manifest-webpack-plugin"); module.exports = { 
  /*...*/ 
  plugins: [ 
    /*...*/ 
    new webpack.optimize.CommonsChunkPlugin({ 
      name: ["vendor", "manifest"], // vendor libs + extracted manifest 
      minChunks: Infinity, 
    }), 
    /*...*/ 
    new ChunkManifestPlugin({ filename: "chunk-manifest.json", manifestVariable: "webpackManifest" }) 
  ]
};

因为我们从入口块(entry chunk)中移除了 manifest,所以我们现在有责任为 webpack 提供它。上面示例中的 manifestVariable 选项是全局变量的名称,webpack 将利用它查找 manifest JSON 对象。这个变量应该在我们引入 bundle 到 HTML 之前就定义好。这是通过在 HTML 中内联 JSON 的内容来实现的。我们的 HTML 头部应该像这样:

<!-- 这里我不明白webpackManifest的作用 -->
<html> 
  <head> 
  <script> 
  //<![CDATA[ window.webpackManifest = {"0":"main.5f020f80c23aa50ebedf.js","1":"vendor.81adc64d405c8b218485.js"} //]]>        
  </script> 
  </head> 
  <body> 
  </body>
</html>

在结束时,文件的哈希值应该基于文件的内容。对此,我们可以使用 webpack-chunk-hash 或者 webpack-md5-hash。
所以最终的 webpack.config.js 看起来像这样:

var path = require("path");var webpack = require("webpack");
var ChunkManifestPlugin = require("chunk-manifest-webpack-plugin");
var WebpackChunkHash = require("webpack-chunk-hash");

module.exports = {
  entry: {
    vendor: "./src/vendor.js", // vendor reference file(s)
    main: "./src/index.js" // application code
  },
  output: {
    path: path.join(__dirname, "build"),
    filename: "[name].[chunkhash].js",
    chunkFilename: "[name].[chunkhash].js"
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: ["vendor", "manifest"], // vendor libs + extracted manifest
      minChunks: Infinity,
    }),
    new webpack.HashedModuleIdsPlugin(),
    new WebpackChunkHash(),
    new ChunkManifestPlugin({
      filename: "chunk-manifest.json",
      manifestVariable: "webpackManifest"
    })
  ]};

使用webpack-dev-server

关于API:https://doc.webpack-china.org/configuration/dev-server/

// package.json
// 其中scripts这样设置
"scripts": {
  "build": "webpack",
  "dev": "webpack-dev-server --devtool eval-source-map --progress --colors"
},
// webpack.config.js
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = function(env) {
  return {
    entry: {
      main: './index.js',
      vendor: ['moment', 'path']
    },
    output: {
      // filename: '[chunkhash].[name].js',
      filename: '[name].js',
      publicPath: "/assets/", 
      path: path.resolve(__dirname, 'build')
    },
    devServer: {
      inline: true,
      port: 8099,
      contentBase: path.join(__dirname, 'build') 
    },
    plugins: [
      new webpack.optimize.CommonsChunkPlugin({
        names: ['vendor', 'manifest']
      }),
      new HtmlWebpackPlugin({
        template: './index.html'
      }),
      // etc.
    ]
  }
}

使用npm run dev的时候,可以看到输出有以下:
不会实际生成文件夹,这一部分,推荐看这里:https://github.com/liangklfangl/webpack-dev-server/commit/9b9b86beffedee9c15c7ba3a807b30eb78d477e9

> webpack-dev-server --devtool eval-source-map --progress --colors

 10% building modules 2/2 modules 0 active
Project is running at http://localhost:8099/
webpack output is served from /assets/
Content not from webpack is served from C:\Users\real\...\build
 10%Hash: d968bc9b6ab05170f44f
Version: webpack 2.2.1
  • 在 dev-server 的两种不同模式之间切换。默认情况下,应用程序启用内联模式(inline
    mode)。这意味着一段处理实时重载的脚本被插入到你的包(bundle)中,并且构建消息将会出现在浏览器控制台。 也可以使用 iframe模式,它在通知栏下面使用 <iframe> 标签,包含了关于构建的消息。
    切换到 iframe 模式:inline:false
    当使用模块热替换时,建议使用内联模式(inline mode)。

  • output.path:指定编译目录而已(/build/),不能用于html中的js引用。

  • output.publicPath/devServer.publicPath:publicPath:虚拟目录,自动指向path编译目录(/assets/ => /build/)。html中引用js文件时,必须引用此虚拟路径(但实际上引用的是内存中的文件,既不是/build/也不是/assets/)。

  • devServer.contentBase:指明应用根目录,与上面两个配置项毫无关联。

所以在我打开localhost:8099的时候,如果设置了contentBase,那么就会跳到contentBase指明的目录,这里是:C:\Users\real\...\build,这个目录是不会自动生成的,如果手动建立了这个目录,就会去找到这个目录下的index.html文件。否则,不能找到。

实际上可以访问的是:localhost:8099/assets/index.html,访问这个文件,会看到我们写的index.html,其中index.html自动引用了生成的main.js、vendor.js、manifest.js。并且当我们修改js文件的时候,页面会自动刷新

热更新

webpack中文网的一个例子:实测可用。
https://doc.webpack-china.org/guides/hmr-react/

我的在这里:http://blog.csdn.net/real_bird/article/details/62927644

require.ensure

参考自:
http://blog.csdn.net/zhbhun/article/details/46826129
https://doc.webpack-china.org/guides/code-splitting-require/

说明: require.ensure在需要的时候才下载依赖的模块,当参数指定的模块都下载下来了(下载下来的模块还没执行),便执行参数指定的回调函数。require.ensure会创建一个chunk,且可以指定该chunk的名称,如果这个chunk名已经存在了,则将本次依赖的模块合并到已经存在的chunk中,最后这个chunk在webpack构建的时候会单独生成一个文件。

考虑下面的文件结构:

.
├── dist
├── js
│   ├── a.js
│   ├── b.js
│   ├── c.js
│   └── entry.js
└── webpack.config.js

entry.js

require('./a');
require.ensure(['./b'], function(require){
    require('./c');
    console.log('done!');
});

a.js

console.log('***** I AM a *****');

b.js

console.log('***** I AM b *****');

c.js

console.log('***** I AM c *****');

webpack.config.js

var path = require('path');

module.exports = function(env) {
    return {
        entry: './js/entry.js',
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname, 'dist'),
            // publicPath: 'https://cdn.example.com/assets/',
            // tell webpack where to load the on-demand bundles.
            publicPath: __dirname + '/dist/',

            pathinfo: true,
            // show comments in bundles, just to beautify the output of this example.
            // should not be used for production.
        }
    }
}

通过执行这个项目的 webpack 构建,我们发现 webpack 创建了 2 个新的 bundle,bundle.js 和 0.bundle.js。

entry.js 和 a.js 被打包进 bundle.js。b.js和c.js被打包进0.bundle.js。0.bundle.js是按需加载的(通过output.publicPath,这里我修改了,以便能正确加载到)。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script src="dist/bundle.js" charset="utf-8"></script>
</head>
<body>

</body>
</html>

打开这个文件后可以看到,它自动加载了0.bundle.js。
这里写图片描述
而在控制台输出的是:

***** I AM a *****
***** I AM c *****
done!

这就说明了虽然require.ensure中虽然依赖了b.js,但是没有require('./b');,所以就没有打印出来。模块虽然下载了,但必须手动require才会执行。就算没有使用require('./c');,0.bundle.js还是会被加载的。注意到,这里是async

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue.js前端面试八股文涵盖了多个方面的知识点。其中包括了CSS、JavaScript、Vue、Webpack、Vite、HTML5新特性等等。在面试中,可能会涉及到一些常见的主题,例如BFC、V8垃圾回收机制、Vite和Webpack的区别、Vue中常见的问题、防抖节流、深拷贝、浅拷贝、盒子模型、作用域、闭包、浏览器等。这些都是前端开发中常见的知识点,掌握它们可以帮助你在面试中更好地回答问题。同时,前后端职责分离也是一个重要的概念,前端负责交互逻辑,后端负责数据处理。然而,Vue.js前端面试八股文不仅仅限于这些内容,还可能包括其他相关的知识点。因此,在准备面试时,建议你全面了解Vue.js和相关技术的知识,以便能够更好地回答面试官的问题。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [2023年前端面试必备最新八股文(基础+进阶内容+持续更新)](https://download.csdn.net/download/qq_38951259/87507329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [VUE 前端 面试 技术 八股文](https://download.csdn.net/download/qq_39258956/88011311)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值