前言
上一节webpack实战之(手把手教你从0开始搭建一个vue项目)最后我们完成了css样式的配置:
webpack.config.js:
const path = require("path");
const config = new (require("webpack-chain"))();
const isDev = process.env.WEBPACK_DEV_SERVER;
config
.context(path.resolve(__dirname, ".")) //webpack上下文目录为项目根目录
.entry("app") //入口文件名称为app
.add("./src/main.ts") //入口文件为./src/main.ts
.end()
.output
.path(path.join(__dirname,"./dist")) //webpack输出的目录为根目录的dist目录
.filename("[name].[hash:8].js")
.end()
.resolve
.extensions
.add(".js").add(".jsx").add(".ts").add(".tsx").add(".vue") //配置以.js等结尾的文件当模块使用的时候都可以省略后缀
.end()
.end()
.module
.rule("type-script")
.test(/\.tsx?$/) //loader加载的条件是ts或tsx后缀的文件
.use("ts-loader")
.loader("ts-loader")
.options({
//ts-loader相关配置
transpileOnly: true,
appendTsSuffixTo: ['\\.vue$']
})
.end()
.end()
.rule("vue")
.test(/\.vue$/)// 匹配.vue文件
.use("vue-loader")
.loader("vue-loader")
.end()
.end()
.rule("sass")
.test( /\.(sass|scss)$/)//sass和scss文件
.use("extract-loader")//提取css样式到单独css文件
.loader(require('mini-css-extract-plugin').loader)
.options({
hmr: isDev //开发环境开启热载
})
.end()
.use("css-loader")//加载css模块
.loader("css-loader")
.end()
.use("postcss-loader")//处理css样式
.loader("postcss-loader")
.options( {
config: {
path: path.resolve(__dirname, "./postcss.config.js")
}
})
.end()
.use("sass-loader")//sass语法转css语法
.loader("sass-loader")
.end()
.end()
.end()
.plugin("vue-loader-plugin")//vue-loader必须要添加vue-loader-plugin
.use(require("vue-loader").VueLoaderPlugin,[])
.end()
.plugin("html")// 添加html-webpack-plugin插件
.use(require("html-webpack-plugin"),[{
template: path.resolve(__dirname,"./public/index.html"), //指定模版文件
chunks:["app"], //指定需要加载的chunk
inject: "body" //指定script脚本注入的位置为body
}])
.end()
.plugin("extract-css")//提取css样式到单独css文件
.use(require('mini-css-extract-plugin'), [{
filename: "css/[name].css",
chunkFilename: "css/[name].css"
}])
.end()
.devServer
.host("0.0.0.0") //为了让外部服务访问
.port(8090) //当前端口号
.hot(true) //热载
.open(true) //开启页面
module.exports = config.toConfig();
配置
babel
看一下我们当前项目中的测试代码,src/app.vue:
<template>
<div class="app-container">{
{this.msg}}</div>
</template>
<script lang="ts">
import {Vue, Component} from "vue-property-decorator";
@Component
export default class App extends Vue {
msg="hello world";
user={
name: "yasin"
};
created(){
const name=this.user?.name;
console.log("name");
}
}
</script>
<style scoped lang="scss">
.app-container{
color: red;
}
</style>
比如我们需要用到最新的optional-chaining
语法:
const name=this.user?.name;
我们试着运行一下我们的demo:
...
ERROR in ./src/app.vue?vue&type=script&lang=ts& (./node_modules/ts-loader??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/app.vue?vue&type=script&lang=ts&) 12:31
Module parse failed: Unexpected token (12:31)
File was processed with these loaders:
* ./node_modules/ts-loader/index.js
* ./node_modules/vue-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| }
| created() {
> const name = this.user?.name;
| console.log("name");
| }
@ ./src/app.vue?vue&type=script&lang=ts& 1:0-160 1:176-179 1:181-338 1:181-338
@ ./src/app.vue
@ ./src/main.ts
@ multi ./src/main.ts
可以发现,报错了! 提示我们“该语法解析器不能解析”,有小伙伴可能发现了,在我们demo中我们还用到了:
import {Vue, Component} from "vue-property-decorator";
@Component
export default class App extends Vue {
装饰器语法,那demo之前也没报错啊,为什么呢? 因为我们用的是ts的解析器,ts解析器是可以解析装饰器这种语法的:
<script lang="ts">
我们把lang="ts"
去掉试试:
<template>
<div class="app-container">{
{this.msg}}</div>
</template>
<script>
import {Vue, Component} from "vue-property-decorator";
@Component
export default class App extends Vue {
msg="hello world";
user={
name: "yasin"
};
created(){
const name=this.user?.name;
console.log("name");
}
}
</script>
<style scoped lang="scss">
.app-container{
color: red;
}
</style>
ERROR in ./src/app.vue?vue&type=script&lang=js& (./node_modules/vue-loader/lib??vue-loader-options!./src/app.vue?vue&type=script&lang=js&) 8:0
Module parse failed: Unexpected character '@' (8:0)
File was processed with these loaders:
* ./node_modules/vue-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| import {
Vue, Component} from "vue-property-decorator";
|
> @Component
| export default class App extends Vue {
| msg="hello world";
@ ./src/app.vue?vue&type=script&lang=js& 1:0-115 1:131-134 1:136-248 1:136-248
@ ./src/app.vue
@ ./src/main.ts
@ multi ./src/main.ts
ok! 可以看到,这次报的是装饰器语法解析失败了,知道原因后,我们该怎么解决呢? 看过前面babel系列文章的童鞋应该是立马就想到了babel,那么接下来我们就配置一下babel。
@babel/core(babel核心)
yarn add -D @babel/core || npm install -D @babel/core
@babel/preset-env (env预设)
做es6语法转换、添加polyfill。
yarn add -D @babel/preset-env || npm install -D @babel/preset-env
@babel/plugin-transform-runtime (运行时插件)
添加一些babel转换时候的帮助函数。
yarn add -D @babel/plugin-transform-runtime || npm install -D @babel/plugin-transform-runtime
babel-loader (es加载器)
yarn add -D babel-loader || npm install -D babel-loader
core-js (preset-env设置polyfill的依赖)
yarn add -D core-js || npm install -D core-js
ok, 安装完babel的一些依赖后,我们开始配置webpack,首先是对js、jsx的babel配置:
.module
.rule('js')
.test(/\.m?jsx?$/) //对mjs、mjsx、js、jsx文件进行babel配置
.exclude
.add(filepath => {
// Don't transpile node_modules
return /node_modules/.test(filepath)
})
.end()
.use("babel-loader")
.loader("babel-loader")
.end()
.end()
然后是ts、tsx的配置:
.rule("type-script")
.test(/\.tsx?$/) //loader加载的条件是ts或tsx后缀的文件
.use("babel-loader")
.loader("babel-loader")
.end()
整个配置文件,webpack.config.js:
const path = require("path");
const config = new (require("webpack-chain"))();
const isDev = process.env.WEBPACK_DEV_SERVER;
config
.context(path.resolve(__dirname, ".")) //webpack上下文目录为项目根目录
.entry("app") //入口文件名称为app
.add("./src/main.ts") //入口文件为./src/main.ts
.end()
.output
.path(path.join(__dirname,"./dist")) //webpack输出的目录为根目录的dist目录
.filename("[name].[hash:8].js")
.end()
.resolve
.extensions
.add(".js").add(".jsx").add(".ts").add(".tsx").add(".vue") //配置以.js等结尾的文件当模块使用的时候都可以省略后缀
.end()
.end()
.module
.rule('js')
.test(/\.m?jsx?$/) //对mjs、mjsx、js、jsx文件进行babel配置
.exclude
.add(filepath => {
// Don't transpile node_modules
return /node_modules/.test(filepath)
})
.end()
.use("babel-loader")
.loader("babel-loader")
.end()
.end()
.rule("type-script")
.test(/\.tsx?$/) //loader加载的条件是ts或tsx后缀的文件
.use("babel-loader")
.loader("babel-loader")
.end()
.use("ts-loader")
.loader("ts-loader")
.options({
//ts-loader相关配置
transpileOnly: true,
appendTsSuffixTo: ['\\.vue$']
})
.end()
.end()
.rule("vue")
.test(/\.vue$/)// 匹配.vue文件
.use("vue-loader")
.loader("vue-loader")
.end()
.end()
.rule("sass")
.test( /\.(sass|scss)$/)//sass和scss文件
.use("extract-loader")//提取css样式到单独css文件
.loader(require('mini-css-extract-plugin').loader)
.options({
hmr: isDev //开发环境开启热载
})
.end()
.use("css-loader")//加载css模块
.loader("css-loader")
.end()
.use("postcss-loader")</