学习webpack的笔记

好久没有写日记了。。。
今天我专心学习webpack,跟着网上的文章请练完这16个webpack小例子
翻译阮一峰大神的demo来学。

Demo01:Entry file(入口文件)

首先下载来的webpack版本是4.6.0
我写好package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open",    //  npm run dev 热更新
    "build": "webpack -p"    //  npm run build  打包
  },

执行语句npm run dev,发现有错误,啊,我才开始学,就报错,内容如下

The CLI moved into a separate package: webpack-cli.
Please install 'webpack-cli' in addition to webpack itself to use the CLI.
-> When using npm: npm install webpack-cli -D
-> When using yarn: yarn add webpack-cli -D

要命啊,我不懂啊,我之前命名全局安装过脚手架,为什么他现在又要我安装一次,哎?-D是什么鬼,好的,百度
-D原来就是--save-dev。。。。
百度后,得知,webpack4.0开始就有些不同,根据网上经验者提及,如

在webpack 3中,webpack本身和CLI都在同一个包中,但是在版本4中,他们将两者分开来更好地管理它们。

所以我要重新装一次CLI....

在项目目录下要本地安装webpack
npm install webpack-cli -D

webpack.config.js文件的变化
webpack.config.js里的配置,不再支持 module下的loaders,需要把loaders改成rules。
在项目目录下必须使用配置文件webpack.config.js

即如下:

// webpack 必须采用 commonjs 写法

//专门处理路径用的,以当前路径解析出一个绝对路径
let path = require('path');
console.log(path.resolve('./dist'));
console.log(path.resolve('./dist'));
module.exports = {

    //打包的入口文件webpack会自动查找相关的依赖进行打包
    entry: './src/main.js',

    output: {
        filename: 'bundle.js', //打包后的名字
        path: path.resolve('./dist'), //必须使用个绝对路径
    },
    module: {
        rules: [
            //针对css文件,进行对应的loader处理
            { test: /\.css$/, loader: "style-loader!css-loader" }
        ]
    }
};

惊喜 webpack --display-error-details//带上参数可以找出详细的错误信息

Demo02: Multiple entry files (多入口文件)

疑惑:这个。。。都翻译成多页面XXX的,我没有看出来哪里多页面啊?这不是多个js文件合成一个吗?
有一个提示,又是webpack4.0版本与之前的差异

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
只需要在package.json中添加配置项:

"scripts": {

  "dev": "webpack --mode development",

  "build": "webpack --mode production"

}

接着报错了。。。找不到模块???

ERROR in Entry module not found: Error: Can't resolve './src' in 'E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles'
resolve './src' in 'E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles'
  using description file: E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles\package.json (relative path: .)
    Field 'browser' doesn't contain a valid alias configuration
    using description file: E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles\package.json (relative path: ./src)
      no extension
        Field 'browser' doesn't contain a valid alias configuration
        E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles\src doesn't exist
      .wasm
        Field 'browser' doesn't contain a valid alias configuration
        E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles\src.wasm doesn't exist
      .mjs
        Field 'browser' doesn't contain a valid alias configuration
        E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles\src.mjs doesn't exist
      .js
        Field 'browser' doesn't contain a valid alias configuration
        E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles\src.js doesn't exist
      .json
        Field 'browser' doesn't contain a valid alias configuration
        E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles\src.json doesn't exist
      as directory
        E:\godown.work\webpack_study\myseft-demos\MultipleEntryFiles\src doesn't exist

终于找到原因了,写错单词

module.exports = {  // 写成module.exports
    entry:{            // 写成enter
        bundle1: "./main1.js",
        bundle2: "./main2.js"
    },
    output: {
        filename: '[name].js'
    }
};

Demo03: Babel-loader(编译器可以将es6语法转成低版本[如es5语法]提高兼容性)

大神配的是react,我要配vue...一把辛酸泪

  • main.js
import Vue from 'vue'
import App from './App.vue'

new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})
  • App.vue
<template>
  <div id="app">
    <h3>拉开大接访卡拉集散地立刻飞机阿斯科利的解放昆仑山搭街坊</h3>
  </div>
</template>
<script>
export default {
  name: 'app',
}
</script>
<style>

</style>
  • index.html
<html>
    <body>
        <script src="./main.js"></script>
        <div id="app"></div>
    </body>
</html>
  • 错误的package.json
{
  "name": "babyloader",
  "version": "1.0.0",
  "scripts": {
    "dev": "webpack-dev-server --open --development",
    "build": "webpack -p --production"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.6.0"
  }
}

先不管我webpack.config.js配的怎么样,假设我config.js配好了,然后我一运行npm run dev
不知道为什么报错。。。很奇怪,给我展示了一些配置help

Initialization:
  --init             Initializes a new webpack configuration or loads a
                     addon if specified                                [boolean]
  --migrate          Migrate your webpack configuration from webpack 1 to
                     webpack 2                                         [boolean]
  --add              Adds a webpack component to your configuration file
                                                                       [boolean]
  --generate-loader  Generates a new webpack loader project            [boolean]
  --generate-plugin  Generates a new webpack plugin project            [boolean]

Config options:
  --config               Path to the config file
                         [string] [default: webpack.config.js or webpackfile.js]
  --config-register, -r  Preload one or more modules before loading the webpack
                         configuration      [array] [default: module id or path]
  --config-name          Name of the config to use                      [string]
  --env                  Environment passed to the config, when it is a function
  --mode                 Mode to use
                                 [string] [choices: "development", "production"]
...
...
...
Unknown argument: development
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! babyloader@1.0.0 dev: `webpack-dev-server --open --development`  //  这是重点,原来我没有写mode
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the babyloader@1.0.0 dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Administrator\AppData\Roaming\npm-cache\_logs\2018-04-18T07_19_32_191Z-debug.log
  • 正确的package.json
{
  "name": "babyloader",
  "version": "1.0.0",
  "scripts": {
    "dev": "webpack-dev-server --open --mode development",
    "build": "webpack -p --mode production"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.6.0"
  }
}
module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['es2015']
                  }
                }
            }
        ]
    }
}

新建一个.babelrc文件,内容如下

{
    "presets": ["es2015", "stage-2"],
    "plugins": ["transform-runtime"]
}

配合这篇文章,再找以前的package.json看需要装些什么,差点忘记装vue,vue-loader

npm install vue-loader vue-loader
npm install vue
npm install babel-plugin-transform-runtime -D
提示要装preset "es2015"
npm install babel-preset-es2015 -D
提示要装preset "stage-2"
npm install babel-preset-stage-2 -D
提示要装  Can't resolve 'css-loader'
npm install css-loader -D
终端终于没有报错,但是浏览器控制台报错了
Uncaught SyntaxError: Unexpected identifier
先不管它,看看上面那篇文章跟以前的package.json还有什么差要安装的
npm install babel-core babel-runtime babel-preset-env -D

再配置一次webpack.config.js

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['es2015','env']
                  }
                }
            },
            {
                test: /\.vue$/, 
                exclude: /node_modules/,
                use: 'vue-loader'
            },
        ]
    }
}
  • 最后的package.json
{
  "name": "babyloader",
  "version": "1.0.0",
  "scripts": {
    "dev": "webpack-dev-server --open --mode development",
    "build": "webpack -p --mode production"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "vue": "^2.5.16"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-stage-2": "^6.24.1",
    "babel-runtime": "^6.26.0",
    "css-loader": "^0.28.11",
    "vue-html-loader": "^1.2.4",
    "vue-loader": "^14.2.2",
    "vue-template-compiler": "^2.5.16",
    "webpack": "^4.6.0"
  }
}

编译器终端没有报错,但是打开浏览器却报错了



2018-04-19 更新

搞了一下午,都不知道为什么,我放开了,继续走下一个demo

我回来了,index.html的main.js改成bundle.js并且放div下面(因为js中挂载#app)
index.html的main.js改成bundle.js原因:
main.js只是webpack的入口文件,打包之后就不再是什么main.js了,而我index.html引用了main.js,而浏览器是不支持你所写的main.js模块化的方式。下面问题的回答那个人说的
webpack配置css-loader后,在m浏览器报错 require is not defined

Demo04: css-loader

运行一峰大神的代码没有报错的,但是为什么我完完全全copy一份运行,要我安装style-loader,css-loader的我都安装好了啊。。。为什么我浏览器会报这样的错



啊!!!!!!!!!!!!为什么要要这样对我!!!!!!!!!!!
这里的原因也是03demo那样,index.html引了main.js

Demo05: Image loader

要安装url-loader、file-loader
webpack.config.js

module.exports = {
    entry: './main.js',
    output: {
        path: '/dist',
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                use: [
                    {
                      loader: 'url-loader',
                      options: {
                        limit: 8192,     // 低于指定的限制时,可以返回一个 DataURL。
                        mimetype: 'image/jpeg',       // 指定MIME类型
                        fallback: 'responsive-loader'   // 当文件大于限制时,指定loader处理,默认file-loader
                      }
                    }
                ]
            }
        ]
    }
}
预测结果
认证

Demo06: CSS Module

实用性不强啊,我不干~跳过

Demo07: UglifyJs Plugin

压缩代码,我发现我没有装uglifyjs-webpack-plugin运行dev的时候node_modules文件夹下有一个.cache缓存问价夹,里面有uglifyjs-webpack-plugin文件夹。自带的??

  • index.html
<html>
    <body>
        <h1>js压缩</h1>
        <script src="./bundle.js"></script>
    </body>
</html>
  • main.js
function a(s){
    let a = 1;
    alert(s);
    return a;
}
const t = a("hello sb");
console.log(t);
  • package.json
{
  "name": "uglywebpackplugin",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open --mode development",
    "build": "webpack -p --mode production"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "uglifyjs-webpack-plugin": "^1.2.5",
    "webpack": "^4.6.0"
  }
}
  • webpack.config.js
const webpack = require('webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    plugins: [
        new UglifyJsPlugin()
    ]
}

好奇怪。。我有es6语法,居然不装babel-loader也可以运行。。。神了。。。

Demo08: HTML Webpack Plugin and Open Browser Webpack Plugin

  • package.json
{
  "name": "html_openbrowser",
  "version": "1.0.0",
  "scripts": {
    "dev": "webpack-dev-server --open --mode development",
    "build": "webpack -p --colors"
  },
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^3.2.0",
    "open-browser-webpack-plugin": "0.0.5",
    "webpack": "^4.6.0",
    "webpack-cli": "^2.0.14"
  }
}
  • main.js
document.write('<h1>html-webpack-plugin可以打包多个页面</h1>')
  • template.html
<html>
    <head></head>
    <body>
        
    </body>
</html>
  • webpack.config.js
const HtmlwebpackPlugin = require('html-webpack-plugin');   // 需要本地装webpack
const OpenBrowserPlugin = require('open-browser-webpack-plugin');
const path = require('path');
module.exports = {
    entry: './main.js',
    output: {
        path: path.resolve(__dirname, "dist"), // string
        // 所有输出文件的目标路径
        // 必须是绝对路径(使用 Node.js 的 path 模块)
        filename: "./js/bundle.js", // string 相对路径
        // 「入口分块(entry chunk)」的文件名模板(出口分块?)

        // publicPath: "/assets/", // string
        // 输出解析文件的目录,url 相对于 HTML 页面
    },
    plugins: [
        new HtmlwebpackPlugin({
            template: "./template.html",
            filename: "./index.html",
            // 1、filename配置的html文件目录是相对于webpackConfig.output.path路径而言的,不是相对于当前项目目录结构的。
            // 2、指定生成的html文件内容中的link和script路径是相对于生成目录下的,写路径的时候请写生成目录下的相对路径。
            inject: "head",
            minify: true    // 压缩html
        })
    ]
}
打包出来后的目录

dist目录下的index.html

dist/js目录下的bundle.js

我这里的webpack.config.js没有配自动打开网页,可能多页面的时候设置比较好一点。


2018-04-20 更新

Demo09: 设置环境变量

因为涉及的是process.env,node的变量,我一直搞不懂这什么鬼来的,看完在找一份相对完整的Webpack项目配置指南么?这里有webpack环境变量配置问题?
关于process这个属性讲解 Node.js中环境变量process.env的一些事详解
现在我终于有点理解了。

只要输出一下process.env,你就知道这个env对象根本没有DEBUG、NODE_ENV这些,因为这些都是我们手动挂载上去的,这是(区分环境的)标记。

// webpack.config.js
module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    }
}
// console.log('process         ',process);
console.log('process.env         ',process.env);
console.log('process.env.NODE_ENV         ',process.env.NODE_ENV);
console.log('process.env.DEBUG         ',process.env.DEBUG);

然后我就开始写一个demo
package.json

{
  "name": "setenv",
  "version": "1.0.0",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open --mode development"
  },
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.6.0",      // 这个是webpack4.6标配
    "webpack-cli": "^2.0.14"      // 这个是webpack4.6标配
  }
}

main.js

function main(){
    console.log(1);
}
if(__DEV__){    // DEBUG为true
    main();
}else{
    console.log('DEBUG为false');
}

webpack.config.js

const webpack = require('webpack');
// const path = require('path');

module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    plugins: [
        new webpack.DefinePlugin({
            __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))   // 获取DEBUG的值
        })
    ]
}
console.log('process.env.DEBUG    ',process.env.DEBUG);
console.log('typeof process.env.DEBUG    ',typeof process.env.DEBUG);
console.log("JSON.parse(process.env.DEBUG || 'false')    ",JSON.parse(process.env.DEBUG || 'false'));
console.log("typeof JSON.parse(process.env.DEBUG || 'false')    ",typeof JSON.parse(process.env.DEBUG || 'false'));
console.log("JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))    ",JSON.stringify(JSON.parse(process.env.DEBUG || 'false')));
console.log("typeof JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))    ",typeof JSON.stringify(JSON.parse(process.env.DEBUG || 'false')));
// console.log('process         ',process);
// console.log('process.env         ',process.env);
// console.log('process.env.NODE_ENV         ',process.env.NODE_ENV);
// console.log('process.env.DEBUG         ',process.env.DEBUG);

index.html 这是为了看效果~

<html>
    <body>
        <script src="./bundle.js"></script>
    </body>
</html>

运行npm run dev,好了,发现问题~

挂载失败~

逛到跟我有同样情况出现的人儿~process.env.NODE_ENV在哪儿设置,最终被指引到使用cross-env解决跨平台设置NODE_ENV的问题
这种只能解决在script里设置变量,我想在命令行里设置。。。
向恶势力低头~~~
我发现不用安装这个插件也可,就是在pageage.json配置script属性set就行

Demo10: Code splitting

重点是require.ensure这个api
但是require跟require.ensure好想。。。到底有什么区别~
vue项目优化之按需加载组件-使用webpack require.ensure
vue按需加载组件-webpack require.ensure
12. 异步加载模块 require.ensure

最重点就是这句话了

看文章的例子结合这句话
其次,require.ensure使得dependenciescallback引用的模块会打包到一个chunk中,require引用的模块会打包到bundle.js中。

// firstLoad.js
module.exports = {
    temp: function(b){
        console.log('执行传进来的函数',b());
    }
}

// second.js
module.exports = {
    b:function(){
        return 10;
    }
}

// third.js
module.exports = "我是第三个加载"

// webpack.config.js
module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    }
}
//  main.js

// require(['./third']); // 被打包到0.bundle.js里去
// require('./third'); // 被打包到bundle.js里去  胜出
function a(){
    console.log('a函数开始执行');
    // require(['./third']); // 被打包到0.bundle.js里去
    require.ensure(['./second.js'],function(require){
        // 先加载second.js  注意点:requi.ensure的模块只会被下载下来,不会被执行,只有在回调函数使用require(模块名)后,这个模块才会被执行。
        console.log('require.ensure开始执行');
        var second = require("./second.js");    // 有一个b函数,返回10
        var first = require("./firstLoad.js");  // 有一个temp函数,输出b()
        first.temp(second.b);
        
    },'a')
    // second.js  firstLoad.js  在    a.bundle.js
}
// main();
a();

package.json 就两个依赖 webpack webpack-cli,这里我就不贴了


结果

先加载bundle.js,按需加载a.bundle.js
多看文章~

Demo12: SplitChunksPlugin(Common chunk)

在webpack 4.X中弃用了Common chunk,代替它的是SplitChunksPlugin
官网介绍SplitChunksPlugin的译文
根据该文章 webpack4: 代码分割CommonChunkPlugin的寿终正寝 理解了SplitChunksPlugin,但是真正并没有深入理解到位。里面说的例子都说明一个理,当共同chunk大于30kb(默认30kb)并至少引用一次都会自动分离出来(这个说明还不够严禁,配合配置项才能准确说明)。

  • package.json(因为有es6语法,所以需要babel)
    {
      "name": "splitchunkplugin",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "dev": "webpack-dev-server --open --mode development",
        "build": "webpack -p --mode production"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "babel-core": "^6.26.0",
        "babel-loader": "^7.1.4",
        "babel-plugin-transform-runtime": "^6.23.0",
        "babel-preset-env": "^1.6.1",
        "babel-preset-es2015": "^6.24.1",
        "babel-preset-stage-2": "^6.24.1",
        "babel-runtime": "^6.26.0",
        "css-loader": "^0.28.11",
        "html-webpack-plugin": "^3.2.0",
        "vue-loader": "^14.2.2",
        "vue-template-compiler": "^2.5.16",
        "webpack": "^4.6.0",
        "webpack-cli": "^2.0.15",
        "webpack-dev-server": "^3.1.3"
      },
      "dependencies": {
        "react": "^16.3.2",
        "react-dom": "^16.3.2",
        "vue": "^2.5.16"
      }
    }
    
  • webpack.config.js(多入口文件引用相同js,输出文件名由entry.key决定,chunkname由splitChunks.name决定)
      module.exports = {
          entry: {
              main1: './main1.js',
              main2: './main2.js',
              main3: './main3.js',
              main4: './main4.js',
          },
          output: {
              path: __dirname + '/dist',
              filename: './js/[name].js',
              chunkFilename: './js/[name].js', // 这里输出的chunkname就是splitChunks配置的name
          },
          module: {
              rules: [
                  {
                      test: /\.js$/,
                      exclude: /node_modules/,
                      use: {
                      loader: 'babel-loader',
                      options: {
                          presets: ['es2015','env','stage-2'],
                          plugins: ["transform-runtime"]
                      }
                      }
                  },
                  {
                      test: /\.vue$/, 
                      exclude: /node_modules/,
                      use: 'vue-loader'
                  },
              ]
          },
          optimization: {
              splitChunks: {
                  chunks: "initial",    // 默认all,   initial  分离后   因为改变初始代码块会影响声明在HTML的script标签。
                  minSize: 0,  //  形成一个新代码块最小的体积 byte单位  chunk超过才分离出来  默认30000  太小体积的代码块被分割,可能还会因为额外的请求,拖慢加载性能
                  minChunks: 1,   // (默认是1):在分割之前,这个代码块最小应该被引用的次数(译注:保证代码块复用性,默认配置的策略是不需要多次引用也可以被分割)
                  maxAsyncRequests: 5,    // 默认是(5):按需加载时候最大的并行请求数。
                  maxInitialRequests: 3,  // 默认是(3):分离后  一个入口最大的并行请求数
                  automaticNameDelimiter: '~',    // vendors~main1~main2.js,main1~main2.js
                  name: true,
                  cacheGroups: {
                      vendors: {
                          test: /[\\/]node_modules[\\/]/,     // 应用来自node_modules的代码。
                          priority: -10   // 优先级  更高优先级的缓存组可以优先打包所选择的模块
                      },
                      default: {
                          minChunks: 2,
                          priority: -20,
                          reuseExistingChunk: true    // webpack会添加一个只包含运行时(runtime)额外代码块到每一个入口。(译注:这个需要看场景使用,会导致每个入口都加载多一份运行时代码)
                      }
                  }
              }
          }
      }
    

optimization.splitChunks.chunks的值我写了chunks
optimization.splitChunks.chunks的值我写了0
都是为了方便有效果。。。

  • main1.js、main2.js、main3.js、main4.js、apple.js、boy.js
    // main1.js
      import Vue from "vue";
      import Apple from "./apple.js";
    
    // main2.js
      import Vue from "vue";
      import Apple from "./boy.js";
    
    // main3.js
      import React from "react";
      import Apple from "./apple.js";
    
    // main4.js
      import React from "react";
      import Apple from "./boy.js";
    
    // apple.js
      function apple(){
          console.log('这是apple插件');
      }
    
    // boy.js
      function boy(){
          console.log('这是boy插件');
      }
    
结果

默认模式会将所有来自node_modules的模块分配到一个叫vendors的缓存组;
所有重复引用至少两次的代码,会被分配到default的缓存组。

所有重复引用至少两次的代码,会被分配到default的缓存组。这个我之后添加多一个main5.js入口文件引用apple.js打包之后也没有出现default开头的js文件生成,只有 main1~main3~main5.js

打包出来以后,除了自身的输出文件main1/2/3/4.js生成以外,加载入口文件main1、2.js时,都引用了vue,来自于node_modules的模块,所以会有一个 vendors~main1~main2.js文件,同理,会有vendors~main3~main4.js,而main1.js、main3.js引用了apple.js,main2.js、main4.js引用了boy.js,引用的模块不是node_modules的模块,所以没有vendor开头,生成的是main1~main3.jsmain2~main4.js

官方推荐使用默认配置

又不能完全理解每个属性干嘛,还是乖乖的用默认配置吧。。。


2018.04.24更

Demo13: Vendor chunk 这个demo用的也是弃用的Common chunk,就是把第三方库导出来用,这一功能SplitChunksPlugin自动解决了,不写此demo。

Demo14: Exposing global variables

全局暴露变量,说的很简单,但其实里面包含加载方式,运行环境这些东西
这篇文章使我理解externals和libraryTarget的关系。webpack之深入浅出externals
webpack externals 深入理解
这篇文章使我能够理解一点为什么要在html引入js之后,还要在config配置,在js require。webpack的externals的使用

我一开始认为,不把第三方打包到bundle,那安装的时候-D就好了啊,为什么要特意说明不想让webpack打包,直到看到下面这句话。在运行时从外部获取这些扩展依赖,哦,如果-D在生产环境下是没有这个第三方的,他要在生产环境运行这个第三方,所以要暴露~

[externals]防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖

百着百着,看到有人问externalsprovideplugin区别 Webpack ProvidePlugin vs externals?
我想了一下providepluginDemo13: Vendor chunk 最后说到了provideplugin。
说到区别,我也想知道有什么区别,所以我就先搞一下provideplugin

纯净版 require,没有provideplugin,没有externals
  • package.json
{
  "name": "provideplugin_externals",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open --mode development",
    "build": "webpack -p"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.6.0",
    "webpack-cli": "^2.0.15",
    "webpack-dev-server": "^3.1.3"
  },
  "dependencies": {
    "jquery": "^3.3.1"
  }
}
  • webpack.config.js
let Htmlwebpackplugin = require('html-webpack-plugin');
let webpack = require('webpack');
module.exports = {
    entry: './main.js',
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js'
    },
    plugins: [
        new Htmlwebpackplugin({
            template: './index.html',
            inject: 'head',
            filename: 'main.html'
        })
    ]
}
  • main.js
let $ = require('jquery');
 $(function(){
     $('.a').text('wahahahaha');
 })
  • index.html 模版
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>
<body>
    <div class="a"></div>
</body>
</html>

npm run build 运行打包出来以后的size,安装jquery,require('jquery'),打包到bundle了

总结:安装jquery后,require模块会被打包到bundle中

provideplugin

webpack的ProvidePlugin配置
一开始看官网怎么使用这个插件,我还想着究竟要不要本地安装jquery,经过我第一次试验证明,是要安装的。

  • package.json
{
  "name": "provideplugin_externals",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open --mode development",
    "build": "webpack -p"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.6.0",
    "webpack-cli": "^2.0.15",
    "webpack-dev-server": "^3.1.3"
  },
  "dependencies": {
    "jquery": "^3.3.1"   // 本地安装,生产环境需要
  }
}
  • webpack.config.js
let Htmlwebpackplugin = require('html-webpack-plugin');
let webpack = require('webpack');
module.exports = {
    entry: './main.js',
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js'
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery'  // 打包在bundle.js了
        }),
        new Htmlwebpackplugin({
            template: './index.html',
            inject: 'head',
            filename: 'main.html'
        })
    ]
}
  • main.js
$(function(){
    $('.a').text('wahahahaha');
})
// window.onload = function(){
//     document.getElementsByClassName('a')[0].innerHTML = "xixixixixixixixix";
// }
  • index.html 模版
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>
<body>
    <div class="a"></div>
</body>
</html>

npm run build 运行打包出来以后的size,安装jquery,配置provideplugin,被打包进入了bundle

总结:用ProvidePlugin进行实例初始化后,jquery就会被自动加载并导入对应的node模块中(会打包到bundle.js中),不再需要import和require进行引入,本地安装之后,可以直接在代码中使用,你还可以把$换成其他字母

externals
  • package.json
{
  "name": "provideplugin_externals",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --open --mode development",
    "build": "webpack -p"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.6.0",
    "webpack-cli": "^2.0.15",
    "webpack-dev-server": "^3.1.3"
  },
  "dependencies": {
    "jquery": "^3.3.1"   // 本地安装,生产环境需要
  }
}
  • webpack.config.js
let Htmlwebpackplugin = require('html-webpack-plugin');
let webpack = require('webpack');
module.exports = {
    entry: './main.js',
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js'
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery'  // 打包在bundle.js了
        }),
        new Htmlwebpackplugin({
            template: './index.html',
            inject: 'head',
            filename: 'main.html'
        })
    ],
    externals: {  // 注释了这个配置,jquery就会被打包到bundle
        jquery: 'jQuery'
    }
}
  • main.js
let $ = require('jquery');
$(function(){
    $('.a').text('wahahahaha');
})
  • index.html 模版
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>
<body>
    <div class="a"></div>
</body>
</html>
安装jquery,require('jquery'),配置externals,没有打包到bundle

总结:本地安装jquery,require或import引入jquery模块,就被打包到bundle中,但是在config文件中配置externals,jquery就不会被打包到bundle中。
但是,我在html引用了jquery,我就不用在main.js引入直接使用了,而且也不会被打包到bundle中,为什么还要多此一举,在js文件require/import,在config文件配置呢?难道还有人纠结第三方是否打包到bundle?
自问自答:这篇文章使我能够理解一点为什么要在html引入js之后,还要在config配置,在js require。webpack的externals的使用


前段时间我一直看HMR(热替换),中文文档提到需要热替换的js要在最下面加

if (module.hot) {
  module.hot.accept('./library.js', function() {
    // 使用更新过的 library 模块执行某些操作...
  })
}

按着它那里的基础配置确实是可以实现HMR的,但是真正的项目不可能这样吧,难道我没写一个js都要在下面加一块这样的东西哦....太浪费时间了,我宁愿自己从头搭一个小东西,我也不再继续看HMR了,或者后面我会再拾起来。在这个过程中,我有浏览到比较好的教程讲解
7、HMR 模块热加载讲解得很详细,但是我按照他的做法并没有实现,大家可以去试一下。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容