webpack5入门

开发相关版本:

  • webpack: 5.51.1版本

  • webpack-cli: 4.8.0版本

  • node: 14.10.0版本

完整项目地址webpack-learning

1. 初始化项目 

npm init -y

注: -y的含义: yes, 在init的时候省去敲回车的步骤,生成的默认的package.json。 

接着安装webpack、webpack-cli

npm i -D webpack webpack-cli

注: npm i -D是npm install --save-dev的缩写, npm i -S是npm install --save的缩写

新建一个文件夹src,还是使用之前两个js:

greeting.js

export function greeting (name) {
  return "hello " + name;
}

index.js

import { greeting } from './greeting.js';
 
document.write(greeting('world!'))

在package.json里配置打包命令:

"scripts": {
  "build": "webpack ./src/index.js"
},

执行:

npm run build

如果生成了一个dist文件夹,并且内部含有main.js说明已经打包成功了

完整代码地址demo01-init

2. 新增webpack.config.js 

新建config文件夹,接着新建一个webpack.config.js

const path = require("path");
module.exports = {
  mode: "development", // 开发模式
  entry: "./src/index.js",  // 入口文件
  output: {
    filename: "main.js",    // 打包后的文件名称
    path: path.resolve(__dirname, "../dist") // 打包后的目录
  }
};

更改我们的打包命令

"scripts": {
  "build": "webpack --config ./config/webpack.config.js"
},

执行npm run build进行打包

完整代码地址demo02-config

3.配置html模板

3.1 单入口配置

安装html-webpack-plugin

npm i -D html-webpack-plugin

利用html-webpack-plugin去将webpack打包出来的js文件引入到定义好的html模板中, 在根目录新建public,里面新建一个index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>HtmlWebpackPlugin</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
  </body>
</html>

修改webpack.config.js

引入html-webpack-plugin,加上plugins

const HtmlWebpackPlugin = require("html-webpack-plugin");
//...
module.exports = {
  // ....
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html")
    })
  ]
}

执行npm run build就可以看到main.js已经引入到html页面中:

如果我们需要频繁的修改js,但要实时查看效果的话则需要引入webpack-dev-server来解决这个问题。

webpack-dev-server 为你提供了一个基本的 web server,并且具有 live reloading(实时重新加载) 功能

npm i -D webpack-dev-server

 修改配置文件,告知 dev server,从什么位置查找文件:

同时配置热更新

webpack.config.js

const path = require("path");
const webpack = require('webpack');
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  mode: "development", // 开发模式
  entry: path.resolve(__dirname,'../src/index.js'),  // 入口文件
  // web server
  devServer: {
    static: {
      directory: path.resolve(__dirname, '../dist'), // 打包后的文件路径
    },
    open: true,    //自动打开浏览器
    compress: true,  //启动gzip压缩
    port: 9000   // 端口号
  },
  output: {
    filename: "main.js", // 打包后的文件名称
    path: path.resolve(__dirname, "../dist"), // 打包后的目录
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html")
    }),
    new webpack.HotModuleReplacementPlugin()
  ]
};

接着修改package.json里配置命令:

"scripts": {
    "dev": "webpack-dev-server --config ./config/webpack.config.js",
    "build": "webpack --config ./config/webpack.config.js"
  },

为了在浏览器里看效果,我们可以修改src/index.js

import { greeting } from "./greeting.js";
document.getElementById("app").textContent = greeting("world!");

执行npm run dev就可以启动浏览器看实际效果了:

完整代码地址demo03-singlepage 

3.2 多入口配置

还是利用html-webpack-plugin来解决, 只是生成多个html-webpack-plugin实例来解决这个问题

在src文件夹下新建search.js

search.js

document.getElementById("app").textContent = "我是search页面";

修改webpack.config.js里面的plugins

// ...
module.exports = {
  // ...
  plugins: [
    new HtmlWebpackPlugin({
      template:path.resolve(__dirname,'../public/index.html'),
      filename:'index.html',
      chunks:['main'] 
    }),
    new HtmlWebpackPlugin({
      template:path.resolve(__dirname,'../public/index.html'),
      filename:'search.html',
      chunks:['search'] // 与入口文件对应的模块名
    })
  ]
}

先执行npm run build看下打包后生成的文件:

执行npm run dev看下实际效果:

两个页面都正常

完整代码地址demo04-multipage 

3.3 利用glob对页面需要打包文件的路径进行处理

glob 在webpack中对文件的路径处理非常之方便,比如当搭建多页面应用时就可以使用glob对页面需要打包文件的路径进行很好的处理

安装glob

npm i -D glob

我们先调整下src中目录结构

然后在根目录新建一个getMultiPageConfig.js

getMultiPageConfig.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const glob = require("glob");

exports.getMultiPageConfig = function () {
  const entries = {}, htmlPlugins = [];
  // glob同步方法获取
  const entryFiles = glob.sync(path.resolve(__dirname, "./src/js/*/index.js"));
  // ['/xxx/demo05-glob-multpage/src/js/index/index.js', '/xxx/demo05-glob-multpage/src/js/search/index.js']
  entryFiles.forEach((ele) => {
    let match = ele.match(/src\/js\/(.*)\/index\.js/);
    let pageName = match && match[1];
    if (pageName) {
      entries[pageName] = ele;
      htmlPlugins.push(
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, "./public/index.html"),
          filename: `${pageName}.html`,
          chunks: [pageName],
        })
      );
    }
  });
  return {
    entries,
    htmlPlugins,
  };
};

接着修改webpack.config.js 

const path = require("path");
const { getMultiPageConfig } = require("../getMultiPageConfig");
const { entries, htmlPlugins } = getMultiPageConfig();
module.exports = {
  mode: "development", // 开发模式
  // 入口文件
  entry: entries,
  // web server
  devServer: {
    static: {
      directory: path.resolve(__dirname, '../dist'), // 打包后的文件路径
    },
    open: true,    //自动打开浏览器
    compress: true,  //启动gzip压缩
    port: 9000   // 端口号
  },
  output: {
    filename: "[name].js", // 打包后的文件名称
    path: path.resolve(__dirname, "../dist"), // 打包后的目录
  },
  plugins: htmlPlugins
};

 执行npm run dev/build结果都正常

完整代码地址demo05-glob-multpage 

3.4 webpack5之前加入clean-webpack-plugin清理打包目录

使用 clean-webpack-plugin清除dist文件夹

安装 clean-webpack-plugin

npm i -D clean-webpack-plugin

接着修改webpack.config.js , 引入clean-webpack-plugin,及修改plugins

const { CleanWebpackPlugin } = require("clean-webpack-plugin");
//...
module.exports = {
  // ....
  plugins: [new CleanWebpackPlugin()].concat(htmlPlugins)
}

3.5 webpack5 配置output.clean清理打包目录

//...
module.exports = {
  // ....
  output: {
    clean: true,
    // ...
  }
}

完整代码地址demo05-glob-multpage  

4.引入CSS

4.1 引入css、less、scss等

先修改public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>webpack learning</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <h1>Hello World!</h1>
    <h2>Hello World!</h2>
    <h3>Hello World!</h3>
    <h4>Hello World!</h4>
    <h5 id="title"></h5>
  </body>
</html>

我们在src里创建assets文件夹, 接着在该文件夹下创建index.css、index.less、index.scss, search.less

index.css

h1 {
    color: red;
}

index.less

@color: blue;
h2 {
    color: @color;
}

index.scss

$color:yellow;
h3 {
    color: $color;
}

search.less 

@color:wheat;
h1, h2, h3 {
    color: @color;
}

修改src/index/index.js

index.js

import { greeting } from "./greeting.js";
import '../../assets/index.css';
import '../../assets/index.less';
import '../../assets/index.scss';
document.getElementById('title').textContent = greeting("world!");

由于webpack开箱即用只支持JS和JSON两种文件类型,此时我们需要利用style-loader、css-loader来解析css文件, 利用less、less-loader来解析.less文件,利用sass、sass-loader来解析.scss文件

我们一次性安装这些loader

npm i -D style-loader css-loader less less-loader sass sass-loader

接着修改webpack.config.js 

//...
module.exports = {
  // ....
  module:{
    rules:[
      {
        test:/\.css$/,
        use:['style-loader','css-loader'] // 从右向左解析原则
      },
      {
        test:/\.less$/,
        use:['style-loader','css-loader','less-loader'] // less的loader
      },
      {
        test:/\.scss$/,
        use:['style-loader','css-loader','sass-loader'] // scss的loader
      }
    ]
  }
}

执行npm run dev,可以看出引入的样式文件都以style的方式引入到html页面中

完整代码地址demo06-css  

4.2 拆分css成独立的文件

webpack 4.0以前,我们通过extract-text-webpack-plugin插件,把css样式从js文件中提取到单独的css文件中。webpack4.0以后,官方推荐使用mini-css-extract-plugin插件来打包css文件

安装mini-css-extract-plugin

npm i -D mini-css-extract-plugin

修改配置如下: 

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
//...
module.exports = {
  // ....
  plugins: [
    new CleanWebpackPlugin(),
    ...htmlPlugins,
    new MiniCssExtractPlugin({
      filename: "[name].[hash].css",
      chunkFilename: "[id].css",
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"], // 从右向左解析原则
      },
      {
        test: /\.less$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"],
      },
      {
        test: /\.scss$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
      }
    ]
  }
}

执行npm run build,css被打包出单独成一个文件

 执行npm run dev

完整代码地址demo07-extract   

4.3 为css添加浏览器前缀 

利用postcss-loader、autoprefixer来为css添加浏览器前缀

安装postcss-loader、autoprefixer

npm i -D postcss-loader autoprefixer

为了看实际效果,我们在css文件里加animation样式:

src/index/index.less

@color: blue;
h2 {
    color: @color;
}
.test {
  width: 100px;
  height: 100px;
  background: red;
  position: relative;
  animation: mymove 5s infinite;
}

@keyframes mymove {
  from {
    left: 0px;
  }
  to {
    left: 200px;
  }
}

修改配置webpack.config.js

//...
module.exports = {
  // ....
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"], // 从右向左解析原则
      },
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [["autoprefixer"]],
              },
            },
          },
          "less-loader",
        ], // less的loader
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [["autoprefixer"]],
              },
            },
          },
          "sass-loader",
        ], // scss的loader
      }
    ],
  }
}

执行npm  run dev 可以看到animation样式已经加了浏览器前缀 

完整代码地址demo08-autoprefixer    

5.打包图片、媒体、字体等文件

在 webpack5 之前,我们一般都会使用以下几个 loader 来处理一些常见的静态资源,比如 PNG 图片、SVG 图标等等,他们的最终的效果大致如下所示:

  • raw-loader:允许将文件处理成一个字符串导入

  • file-loader :将文件打包导到输出目录,并在 import 的时候返回一个文件的 URI

  • url-loader:当文件大小达到一定要求的时候,可以将其处理成 base64 的 URIS 

先来看看webpack5之前处理图片、媒体、字体等文件的方法

5.1 webpack5之前解决引用文件路径等问题

file-loader就是将文件在进行一些处理后(主要是处理文件名和路径、解析文件url),并将文件移动到输出的目录中

安装file-loader

npm i -D file-loader

在assets里引入test.jpg、test1.jpg、movie.ogg等资源

修改src/index/index.js

import { greeting } from "./greeting.js";
import '../../assets/index.css';
import '../../assets/index.less';
import '../../assets/index.scss';
// 在js中使用图片
import test from "../../assets/test.jpg";
import test1 from "../../assets/test1.jpg";

import movie from "../../assets/movie.ogg";
document.getElementById('title').textContent = greeting("world!");

let img = new Image();
img.src = test;
document.getElementById("testImg").appendChild(img);

let img1 = new Image();
img1.src = test1;
document.getElementById("testImg").appendChild(img1);

let videoDom = document.createElement("video");
videoDom.src = movie;
videoDom.controls = "controls"
document.getElementById("testMedia").appendChild(videoDom);

修改配置文件,加上该loader

//...
module.exports = {
  // ....
  module: {
    rules: [
      {
        test: /\.(gif|png|jpe?g)$/i,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[path][name].[ext]",
            },
          },
        ],
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, //媒体文件
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[path][name].[ext]",
            },
          },
        ],
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, // 字体
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[path][name].[ext]",
            },
          },
        ],
      },
    ],
  }
}

执行npm run build 效果如下:

完整代码地址demo09-file     

5.2 webpack5之前优化图片等问题 

url-loader 一般与file-loader搭配使用,功能与 file-loader 类似,如果文件小于限制的大小。则会返回 base64 编码,否则使用 file-loader 将文件移动到输出的目录中

安装url-loader

npm i -D url-loader

修改配置文件,

//...
module.exports = {
  // ....
  module: {
    rules: [
      {
        test: /\.(gif|png|jpe?g)$/i,
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 1024 * 8, // // 将小于8KB的图片转换成base64的格式
              fallback: {
                loader: "file-loader",
                options: {
                  name: "img/[name].[hash:8].[ext]", // 文件名.hash.文件扩展名 默认格式为[hash].[ext]
                },
              },
            },
          },
        ],
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, //媒体文件
        use: [{
          loader: 'file-loader',
          options: {
            name: 'media/[name].[ext]'
          }
        }]
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, // 字体
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[path][name].[ext]",
            },
          },
        ],
      },
    ],
  }
}

执行npm run dev可以看出小于8kb的图片base64编码了

完整代码地址demo10-url      

5.3 webpack5 内置的 Asset Modules

如今webpack5 提供了内置的静态资源构建能力,我们不需要安装额外的 loader,仅需要简单的配置就能实现静态资源的打包和分目录存放。如下:满足规则匹配的资源就能够被存放在 assets 文件夹下面:

  • asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
  • asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
  • asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
  • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现(默认为8KB)。

修改配置文件

//...
module.exports = {
  // ....
  module: {
    rules: [
      {
        test: /\.(gif|png|jpe?g)$/i,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024,
          },
        },
        generator: {
          filename: 'assets/[hash:8].[name][ext]',
        },
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, //媒体文件
        type: 'asset/resource',
        generator: {
          filename: 'assets/[name][ext]',
        }
      },
    ],
  }
}

 执行npm run build 效果如下

完整代码地址demo10-asset      

6. babel转ES5

在webpack中 默认只能处理部分 ES6的新语法,一些更高级的ES6或ES7的语法,webpack是处理不了的这个时候就需要借助第三方的loader 来帮助webpack 处理这些高级的语法。

Balel 可以帮我我们将高级的语法转为低级的语法

利用babel-loader可以使我们的js代码兼容更多的环境

安装babel-loader @babel/preset-env @babel/core

npm i -D babel-loader @babel/preset-env @babel/core

修改src/index/index.js,加上一些ES6方法

//...省略部分代码

// 箭头函数
let arrowFn = () => console.log("hello babel");
arrowFn();
// 解构赋值
let arr = [1, 2, 3];
let [a, b, c] = arr;
// 拓展运算符
console.log(...arr);
//
const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach((x) => s.add(x));

for (let i of s) {
  console.log(i);
}

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, "done");
  });
}

timeout(100).then((value) => {
  console.log(value);
});

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint("hello world", 50);

修改配置文件,加上babel-loader

//...
module.exports = {
  // ....
  module: {
    rules: [
      {
        test:/\.js$/,
        use:{
          loader:'babel-loader',
          options:{
            presets:['@babel/preset-env']
          },
        },
        exclude: /node_modules/
      },
    ],
  }
}

在npm run dev执行完后发现一个错误

这个报错表面上是由于 async function 语法被 babel 转译之后的代码使用了 regeneratorRuntime 这个变量,但是这个变量在最终的代码里未定义造成的报错。

babel 在转译的时候,会将源代码分成 syntax 和 api 两部分来处理:

  • syntax:类似于展开对象、optional chain、let、const 等语法
  • api:类似于 [1,2,3].includes 等函数、方法

上面的babel-loader只会将 ES6/7/8语法转换为ES5语法,但是对新api并不会转换 例如(promise、Generator、Set、Maps、Proxy等)
此时我们需要借助babel-polyfill来帮助我们转换

安装babel-polyfill

npm i @babel/polyfill

接着在src/index/index.js引入该文件

import "@babel/polyfill";
// ...省略以下代码

执行打包,一切正常,但在这种模式下,babel 会将所有的 polyfill 全部引入导致打包体积过大,而且需要在头部引入该文件,正确的做法是使用按需加载,@babel/preset-env 中有一个配置选项 useBuiltIns,用来告诉 babel 如何处理 api。将 useBuiltIns 改为 "usage",babel 就可以按需加载 polyfill,并且不需要手动引入 @babel/polyfill 

修改配置文件:

//...
module.exports = {
  // ....
  module: {
    rules: [
      {
        test:/\.js$/,
        use:{
          loader:'babel-loader',
          options:{
            presets:['@babel/preset-env']
          },
        },
        exclude: /node_modules/
      },
    ],
  }
}

 同时去掉src/index/index.js中import "@babel/polyfill";

 执行npm run dev看下打包完的index.js

可以看出是按需加载的 

完整代码地址demo11-babel     

7. SplitChunksPlugin

SplitChunksPlugin 插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。

使用 optimization.splitChunks 配置选项

//...
module.exports = {
  // ....
  optimization: {
    splitChunks: {
      chunks: 'all', // 设置为all, chunk可以在异步和非异步chunk之间共享; async 代码分割时对异步代码生效; inital:同步代码有效
      minSize: 20000, // 代码分割最小的模块大小,引入的模块大于 30000B 才做代码分割
      minRemainingSize: 0, 
      minChunks: 1, // 引入的次数大于等于1时才进行代码分割
      maxAsyncRequests: 6, // 按需加载时的最大并行请求数
      maxInitialRequests: 4, // 入口点的最大并行请求数
      automaticNameDelimiter: '~', // 文件生成时的连接符
      cacheGroups: {
        defaultVendors: {
          test: /[\\/]node_modules[\\/]/, // 位于node_modules中的模块做代码分割
          priority: -10, // 根据优先级决定打包到哪个组里,例如一个 node_modules 中的模块进行代码
          reuseExistingChunk: true,
        }, // 分割,,既满足 vendors,又满足 default,那么根据优先级会打包到 vendors 组中。
        default: { // 没有 test 表明所有的模块都能进入 default 组,但是注意它的优先级较低。
          minChunks: 2,
          priority: -20, //  根据优先级决定打包到哪个组里,打包到优先级高的组里。
          reuseExistingChunk: true // //如果一个模块已经被打包过了,那么再打包时就忽略这个上模块
        }
      }
    },
  },
}

完整代码地址demo12-splitChunk       

8. TypeScript

安装 TypeScript compiler 和 loader

npm i -D typescript ts-loader

如果使用第三方类库 一定要记得同时安装此库的类型声明文件 

修改配置

//...
module.exports = {
  // ....
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
}

还需要新增tsconfig.json

{
  // 用来配置编译选项
  "compilerOptions": {
    "outDir": "./dist/",  // 用来指定编译后文件所在的目录
    "noImplicitAny": true,
    "module": "es6",    // 生成的module的形式,esm,cmd,amd
    "target": "es5",    // 生成js 的版本
    "jsx": "react",     // jsx用于的开发环境,preserve/react/RN
    "strict": false,    // 是否严格模式
    "allowJs": true,    // 是否对js文件进行编译,默认是false
    "checkJs": true,  // 检查js代码是否符合逻辑规范,默认是false
    "removeComments": true,   //是否移除注释
    "moduleResolution": "node", // 用于选择模块解析策略 node/classic
    "importHelpers": true, // 指定是否引入tslib里的复制工具函数
    "experimentalDecorators": true, // 用于指定是否启用实验性的装饰器特性
    "esModuleInterop": true, // 通过导入内容创建命名空间,实现CommonJS和ES模块之间的互操作性
    "allowSyntheticDefaultImports": true, // 用于允许从没有默认导出的模块中默认导入
    "sourceMap": true, // 编译时是否生成.map文件
    "baseUrl": ".",// 用于设置解析非相对模块名称的基本目录,相对模块不会受到baseUrl的影响
    //用于指定需要包含的模块,只有在这里列出的模块的声明文件才会被加载
    "types": [],
    // 用于设置模块名到基于baseUrl的路径映射
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    // 指定要包含在编译中的库文件
    "lib": [
      "dom",
      "es5",
      "es6",
      "es2018.promise"
    ]
  },
  // 指定编译的文件,没有include和exclude时候用
  "file": [],
  // 指定待编译的文件
  "include": [
    "src/**/*.ts",
  ],
  // 指定排除的文件
  "exclude": [
    "node_modules"
  ]
}

 完整代码地址demo13-ts  

9. 搭建vue开发环境 

9.1 解析vue文件

vue-loader解析.vue文件, vue-template-compiler 用于编译模板 

安装vue-loader、vue-template-compiler

npm i -D vue-loader vue-template-compiler

在src文件里新建App.vue,index.js

 App.vue

<template>
  <div id="app">{{message}}</div>
</template>

<script>
export default {
  name: "App",
  data() {
      return {
          message: "hello world!"
      }
  }
}
</script>

index.js

import Vue from "vue";
import App from "./App";

new Vue({
  el: '#app',
  render: h => h(App)
})

修改配置文件

主要是配置resolve选项,该选项能设置模块如何被解析

const path = require("path");
const { VueLoaderPlugin } = require("vue-loader");
const webpack = require('webpack');
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  mode: "development", // 开发模式
  entry: path.resolve(__dirname, "../src/index.js"), // 入口文件
  // web server
  devServer: {
    static: {
      directory: path.resolve(__dirname, "../dist"), // 打包后的文件路径
    },
    open: true, //自动打开浏览器
    compress: true, //启动gzip压缩
    port: 9000, // 端口号
  },
  output: {
    clean: true, // 清理 /dist 文件夹
    filename: "main.js", // 打包后的文件名称
    path: path.resolve(__dirname, "../dist"), // 打包后的目录
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
  ],
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: "vue-loader",
      },
    ],
  },
  // 配置模块如何解析
  resolve: {
    alias: {
      vue$: "vue/dist/vue.runtime.esm.js",    // 末尾添加 $,以表示精准匹配
      " @": path.resolve(__dirname, "../src"),
    },
    extensions: ["*", ".js", ".json", ".vue"],  // 尝试按顺序解析这些后缀名。如果有多个文件有相同的名字,但后缀名不同,webpack 会解析列在数组首位的后缀的文件 并跳过其余的后缀
  }
};

 完整代码地址demo14-vue   

9.2 集成vue + typescript开发环境

安装插件

npm i -S vue-class-component vue-property-decorator
npm i -D ts-loader typescript
  • vue-class-component:强化 Vue 组件,使用 TypeScript/装饰器 增强 Vue 组件
  • vue-property-decorator:在 vue-class-component 上增强更多的结合 Vue 特性的装饰器
  • ts-loader:为了让webpack识别 .ts .tsx文件 

配置 webpack

修改entry及配置rules、resolve

const path = require("path");
const { VueLoaderPlugin } = require("vue-loader");
const webpack = require('webpack');
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  mode: "development", // 开发模式
  entry: path.resolve(__dirname, "../src/index.ts"), // 入口文件
  // web server
  devServer: {
    static: {
      directory: path.resolve(__dirname, "../dist"), // 打包后的文件路径
    },
    open: true, //自动打开浏览器
    compress: true, //启动gzip压缩
    port: 9000, // 端口号
  },
  output: {
    clean: true, // 清理 /dist 文件夹
    filename: "main.js", // 打包后的文件名称
    path: path.resolve(__dirname, "../dist"), // 打包后的目录
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
  ],
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: "vue-loader",
      },
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: [
          "babel-loader",
          {
            loader: "ts-loader",
            options: { appendTsxSuffixTo: [/\.vue$/] }
          }
        ]
     },
    ],
  },
  // 配置模块如何解析
  resolve: {
    alias: {
      vue$: "vue/dist/vue.runtime.esm.js",    // 末尾添加 $,以表示精准匹配
      " @": path.resolve(__dirname, "../src"),
    },
    extensions: [".js", ".json", ".vue", '.ts', '.tsx',],  // 尝试按顺序解析这些后缀名。如果有多个文件有相同的名字,但后缀名不同,webpack 会解析列在数组首位的后缀的文件 并跳过其余的后缀
  }
};

 以及加上tsconfig.js,同配置ts配置

让 ts 识别 .vue,在src目录下新建文件vue-shim.d.ts ,在文件中输入代码

// 意思是告诉 TypeScript *.vue 后缀的文件可以交给 vue 模块来处理
declare module '*.vue' {
    import Vue from 'vue';
    export default Vue;
}

改造App.vue

  1. script 标签上加上 lang="ts", 意思是让webpack将这段代码识别为typescript 而非javascript
  2. 修改vue组件的构造方式,详见官方
  3. vue-property-decorator语法改造之前代码
<template>
  <div id="app">{{message}}</div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component({
  name: 'App'
})
export default class extends Vue {
  message = "hello world!"
}
</script>

而在代码中导入 *.vue 文件的时候,需要写上 .vue 后缀。原因还是因为 TypeScript 默认只识别 *.ts 文件,不识别 *.vue 文件

修改index.ts中 import App from "./App.vue";

 完整代码地址demo15-vueTs   

参考资料:

webpack官网

https://juejin.cn/post/6844904031240863758#heading-10

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Webpack 是一个常用于打包 JavaScript 应用程序的工具,它的主要作用是将多个 JavaScript 文件打包成一个或多个文件,并且可以处理其他资源文件,如 CSS、图片等。在实际开发中,随着项目规模的增大,Webpack 打包速度、体积等问题就会变得越来越重要,因此,Webpack 优化也成为一个不可忽视的问题。 以下是一些常见的 Webpack 优化方法: 1. 减少文件搜索范围 Webpack 会遍历整个项目目录来查找符合要求的文件,这个过程会消耗大量的时间和资源。我们可以通过配置 resolve.modules 和 resolve.extensions 来减少搜索范围,从而提升打包速度。 2. 使用 Tree Shaking Tree Shaking 是指通过静态分析,将代码中用不到的部分去除,只打包项目中实际被使用的代码。这样可以减少打包后的文件体积。在实际开发中,我们可以使用 webpack.optimize.UglifyJsPlugin 和 webpack.optimize.AggressiveMergingPlugin 等插件来实现 Tree Shaking。 3. 使用 Code Splitting Code Splitting 是指将应用程序拆分成多个 bundle,使得每个 bundle 只包含应用程序的一部分功能,从而减少每个 bundle 的体积,提高加载速度。在实际开发中,我们可以使用 Webpack 自带的代码拆分功能,或者使用第三方库如 react-loadable、bundle-loader 等来实现 Code Splitting。 4. 使用缓存 Webpack 默认会将每个文件的 Hash 值作为文件名的一部分,这样可以保证文件内容发生变化时,文件名也会发生变化,从而避免浏览器缓存问题。但是,如果没有改变的文件也每次都重新打包,就会导致打包速度变慢。因此,我们可以使用缓存来提高打包速度。在 Webpack 中,我们可以使用 cache-loader 和 hard-source-webpack-plugin 等插件来实现缓存。 5. 使用 CDN 加速 通过使用 CDN(内容分发网络),可以将静态资源文件分发到全球各地的服务器上,从而提高文件加载速度。在 Webpack 中,我们可以使用 HtmlWebpackPlugin 和 Webpack 自带的 publicPath 配置来实现 CDN 加速。 以上是一些常见的 Webpack 优化方法,当然还有很多其他的优化方法,需要根据具体情况进行选择和实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值