vuecli4 启动_vue-cli +typescript+webpack4 项目搭建超详细步骤

本文详细记录了使用VueCLI4搭建Vue+TypeScript+Webpack4项目的过程,包括升级webpack、解决CommonsChunkPlugin报错、处理HtmlWebpackPlugin不兼容、解决VueLoaderPlugin报错、替换extract-text-webpack-plugin、修复npm run build和npm run dev的错误,以及引入TypeScript的配置步骤。通过本文,你可以了解如何在最新技术环境下初始化和配置Vue项目。
摘要由CSDN通过智能技术生成

vue+typescript+webpack4 项目搭建步骤

前言: 由于最近才开始接触Typescript,而后首先就是搭建环境,而网上教程时间比较久并且不全,因此在这里记录下手把手的详细脚印。😂 🎉🎉🎉javascript

源码地址请戳 👇👇👇 vue-ts-initcss

一、初始化项目

vue init webpack vue-ts-init

cd vue-ts-init

npm install

复制代码

脚手架项目webpack版本为3.6.0html

二、webpack@3.6.0升级至webpack@4.37.0

方法一:使用yarn安装vue

yarn upgrade webpack@4.6.0

yarn add webpack-dev-server webpack-cli -D

复制代码

方法二:手动修改package.json中webpack版本,从新安装,完成后java

运行 npm run build, 报错node

一、webpack.optimize.CommonsChunkPlugin

Error: webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks insteadjquery

缘由:CommonsChunkPlugin已被webpack4废弃,推荐使用SplitChunkPlugin抽离公共模块webpack

解决:找到 /build/webpack.prod.conf.js ,去掉以下配置git

new webpack.optimize.CommonsChunkPlugin({

name: 'vendor',

minChunks (module) {

// any required modules inside node_modules are extracted to vendor

return (

module.resource &&

/\.js$/.test(module.resource) &&

module.resource.indexOf(

path.join(__dirname, '../node_modules')

)

)

}

}),

// extract webpack runtime and module manifest to its own file in order to

// prevent vendor hash from being updated whenever app bundle is updated

new webpack.optimize.CommonsChunkPlugin({

name: 'manifest',

minChunks: Infinity

}),

// This instance extracts shared chunks from code splitted chunks and bundles them

// in a separate chunk, similar to the vendor chunk

// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk

new webpack.optimize.CommonsChunkPlugin({

name: 'app',

async: 'vendor-async',

children: true,

minChunks: 3

}),

复制代码

/build/webpack.prod.conf.js,添加es6

const webpackConfig = merge(baseWebpackConfig, {

module: {

rules: utils.styleLoaders({

sourceMap: config.build.productionSourceMap,

extract: true,

usePostCSS: true

})

},

devtool: config.build.productionSourceMap ? config.build.devtool : false,

output: {

path: config.build.assetsRoot,

filename: utils.assetsPath('js/[name].[chunkhash].js'),

chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')

},

// 添加以下配置

optimization: {

splitChunks: {

cacheGroups: {

commons: {

chunks: "all",

minChunks: 2,

maxInitialRequests: 5, // The default limit is too small to showcase the effect

minSize: 0 // This is example is too small to create commons chunks

},

vendor: {

test: /node_modules/,

chunks: "all",

name: "vendor",

priority: 10,

enforce: true

}

}

}

},

......

})

复制代码

optimization: {

//提取公共模块,webpack4去除了CommonsChunkPlugin,使用SplitChunksPlugin做为替代

//主要用于多页面

//例子代码 https://github.com/webpack/webpack/tree/master/examples/common-chunk-and-vendor-chunk

//SplitChunksPlugin配置,其中缓存组概念目前不是很清楚

splitChunks: {

// 表示显示块的范围,有三个可选值:initial(初始块)、async(按需加载块)、all(所有块),默认为all;

chunks: "all",

// 表示在压缩前的最小模块大小,默认为0;

minSize: 30000,

//表示被引用次数,默认为1

minChunks: 1,

//最大的按需(异步)加载次数,默认为1;

maxAsyncRequests: 3,

//最大的初始化加载次数,默认为1;

maxInitialRequests: 3,

// 拆分出来块的名字(Chunk Names),默认由块名和hash值自动生成;设置ture则使用默认值

name: true,

//缓存组,目前在项目中设置cacheGroup能够抽取公共模块,不设置则不会抽取

cacheGroups: {

//缓存组信息,名称能够本身定义

commons: {

//拆分出来块的名字,默认是缓存组名称+"~" + [name].js

name: "test",

// 同上

chunks: "all",

// 同上

minChunks: 3,

// 若是cacheGroup中没有设置minSize,则据此判断是否使用上层的minSize,true:则使用0,false:使用上层minSize

enforce: true,

//test: 缓存组的规则,表示符合条件的的放入当前缓存组,值能够是function、boolean、string、RegExp,默认为空;

test:""

},

//设置多个缓存规则

vendor: {

test: /node_modules/,

chunks: "all",

name: "vendor",

//表示缓存的优先级

priority: 10,

enforce: true

}

}

}

}

复制代码

二、compilation.mainTemplate.applyPluginsWaterfall

再运行 npm run build, 报错

building for production.../Users/xyz_persist/front_end/ts/vue-ts-init2/node_modules/html-webpack-plugin/lib/compiler.js:81

var outputName = compilation.mainTemplate.applyPluginsWaterfall('asset-path', outputOptions.filename, {

^

TypeError: compilation.mainTemplate.applyPluginsWaterfall is not a function

复制代码

缘由:html-webpack-plugin未升级版本致使

解决:升级 html-webpack-plugin 版本

npm i html-webpack-plugin@3.2.0

npm i vue-loader@15.7.1

复制代码

三、Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead

再运行 npm run build, 报错

⠋ building for production...(node:13954) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead

⠼ building for production...(node:13954) UnhandledPromiseRejectionWarning: Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead

复制代码

缘由:extract-text-webpack-plugin还不能支持webpack4.0.0以上的版本

解决:升级 extract-text-webpack-plugin 版本

npm i extract-text-webpack-plugin@next -D

注:extract-text-webpack-plugin做用:

将全部入口chunk中引用的.css抽离到独立的css文件中,而再也不内嵌到JS bundle中。

若是样式文件大小较大,会更快提早加载,由于CSS bundle 会跟 JS bundle并行加载

四、TypeError: Cannot read property 'eslint' of undefined

再运行 npm run build, 报错

TypeError: Cannot read property 'eslint' of undefined

at Object.module.exports (/Users/xyz_persist/front_end/ts/vue-ts-init2/node_modules/eslint-loader/index.js:148:18)

TypeError: Cannot read property 'vue' of undefined

at Object.module.exports (/Users/xyz_persist/front_end/ts/vue-ts-init2/node_modules/vue-loader/lib/loader.js:61:18)

@ ./src/main.js 4:0-24 13:21-24

......

复制代码

缘由:eslint-loader、vue-loader版本问题

解决:

npm i eslint-loader@2.2.1 -D

npm i vue-loader@15.7.1 -D

复制代码

五、Make sure to include VueLoaderPlugin in your webpack config

再运行 npm run build, 报错

ERROR in ./src/App.vue

Module Error (from ./node_modules/vue-loader/lib/index.js):

vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.

@ ./src/main.js 4:0-24 13:21-24

复制代码

缘由:Vue-loader在15.*以后的版本都是 vue-loader的使用都是须要伴生 VueLoaderPlugin的

解决:在/build/webpack.base.conf.js中添加

const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {

......

plugins: [

new VueLoaderPlugin()

],

}

复制代码

六、Error: Path variable [contenthash] not implemented in this context: static/css/[name].[contenthash].css

再运行 npm run build, 报错

缘由:webpack4.x中提取CSS文件应该使用mini-css-extract-plugin,废弃extract-text-webpack-plugin

解决:在/build/webpack.prod.conf.js中

// const ExtractTextPlugin = require('extract-text-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

...

plugins: [

...

// new ExtractTextPlugin({

// filename: utils.assetsPath('css/[name].[contenthash].css'),

// allChunks: true,

// }),

new MiniCssExtractPlugin({

filename: 'css/app.[name].css',

chunkFilename: 'css/app.[contenthash:12].css' // use contenthash *

}),

]

复制代码

再修改/build/utils.js文件

// const ExtractTextPlugin = require('extract-text-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

...

if (options.extract) {

// return ExtractTextPlugin.extract({

// use: loaders,

// fallback: 'vue-style-loader'

// })

// MiniCssExtractPlugin.loader,

return [MiniCssExtractPlugin.loader].concat(loaders)

} else {

return ['vue-style-loader'].concat(loaders)

}

复制代码

至此,npm run build已经可以正常打包,生产环境搞定

七、BaseClient.js?e917:12 Uncaught TypeError: Cannot assign to read only property 'exports' of object '#

运行 npm run dev, 命令行没有报错

打开浏览器,控制台报错 BaseClient.js?e917:12 Uncaught TypeError: Cannot assign to read only property 'exports' of object '#'

at Module.eval (BaseClient.js?e917:12)

at eval (BaseClient.js:42)

at Module../node_modules/webpack-dev-server/client/clients/BaseClient.js (app.js:2061)

at __webpack_require__ (app.js:727)

at fn (app.js:101)

at Module.eval (SockJSClient.js?810f:26)

at eval (SockJSClient.js:137)

at Module../node_modules/webpack-dev-server/client/clients/SockJSClient.js (app.js:2073)

at __webpack_require__ (app.js:727)

at fn (app.js:101)

复制代码

缘由:根据字面意思,猜想是解析JS的时候不认识 exports

解决:/build/webpack.base.conf.js 中 {

test: /\.js$/,

loader: 'babel-loader',

// include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')],

include: [resolve('src'), resolve('test')]

},

复制代码

至此,npm run dev 编译没问题,开发环境搞定!

tips:

webpack4.x版本,其余插件修改: NoEmitOnErrorsPlugin 废弃,使用optimization.noEmitOnErrors替代,在生产环境中默认开启 ModuleConcatenationPlugin 废弃,使用optimization.concatenateModules替代,在生产环境默认开启 NamedModulesPlugin 废弃,使用optimization.namedModules替代,在生产环境默认开启 uglifyjs-webpack-plugin升级到了v1.0版本,默认开启缓存和并行功能 CommonsChunkPlugin 被删除

八、总结

用于进行文件分离的内置插件 webpack.optimize.CommonsChunkPlugin ,在Webpack 4.x中,咱们借助于config.optimization来实现

用于压缩JS和CSS的内置插件webpack.optimize.UglifyJsPlugin 、 webpack.optimize.OptimizeCSSPlugin ,在Webpack 4.x中都取消了,可是可以使用UglifyJsPlugin及OptimizeCSSPlugin插件来代替

用于提取CSS到单独文件的插件extract-text-webpack-plugin , 在webpack 4.x中则应该使用mini-css-extract-plugin

Webpack 4.x版本,Vue项目的vue-loader也必须更新到15.0以上版本

三、Vue 引入 TypeScript

一、安装插件

npm i vue-class-component vue-property-decorator --save

npm i ts-loader typescript tslint tslint-loader tslint-config-standard --save-dev

复制代码

这些库大致的做用:

vue-class-component:强化 Vue 组件,使用 TypeScript/装饰器 加强 Vue 组件

vue-property-decorator:在 vue-class-component 上加强更多的结合 Vue 特性的装饰器

ts-loader:TypeScript 为 Webpack 提供了 ts-loader,其实就是为了让webpack识别 .ts .tsx文件

tslint-loader跟tslint:我想你也会在.ts .tsx文件 约束代码格式(做用等同于eslint)

tslint-config-standard:tslint 配置 standard风格的约束

二、配置 webpack

找到/build/webpack.base.conf.js

将 entry.app 将main.js 改为 main.ts,顺便把项目文件中的main.js也改为main.ts, 里面内容保持不变

entry: {

app: './src/main.ts'

}

复制代码

找到resolve.extensions 里面加上.ts 后缀 (是为了以后引入.ts的时候不写后缀)

resolve: {

extensions: ['.js', '.vue', '.json', '.ts'],

alias: {

'@': resolve('src')

}

}

复制代码

找到module.rules 添加webpack对.ts的解析

module: {

rules: [

....

// 新增如下配置

{

test: /\.tsx?$/,

exclude: /node_modules/,

use: [

"babel-loader",

{

loader: "ts-loader",

options: { appendTsxSuffixTo: [/\.vue$/] }

},

{

loader: 'tslint-loader'

}

]

},

....

}

}

复制代码

注:ts-loader 会检索当前目录下的 tsconfig.json 文件,根据里面定义的规则来解析.ts文件(就跟.babelrc的做用同样),tslint-loader 做用等同于 eslint-loader

三、添加 tsconfig.json

在根路径下建立tsconfig.json文件,完整配置见tsconfig.json

这是我本地的配置

{

"include": [

"src/**/*"

],

"exclude": [

"node_modules"

],

"compilerOptions": {

// 解析非相对模块名的基准目录

"baseUrl": ".",

// 指定特殊模块的路径

"paths": {

"@/*": ["*", "src/*"]

},

"jsx": "preserve",

"jsxFactory": "h",

// 容许从没有设置默认导出的模块中默认导入

"allowSyntheticDefaultImports": true,

// 启用装饰器

"experimentalDecorators": true,

// 容许编译javascript文件

"allowJs": true,

// 采用的模块系统

"module": "esnext",

// 编译输出目标 ES 版本

"target": "es5",

// 如何处理模块

"moduleResolution": "node",

// 将每一个文件做为单独的模块

"isolatedModules": true,

// 编译过程当中须要引入的库文件的列表

"lib": [

"dom",

"es5",

"es6",

"es7",

"es2015.promise"

],

"sourceMap": true,

"pretty": true

}

}

复制代码

贴一份参考的配置

{

// 编译选项

"compilerOptions": {

// 输出目录

"outDir": "./output",

// 是否包含能够用于 debug 的 sourceMap

"sourceMap": true,

// 以严格模式解析

"strict": true,

// 采用的模块系统

"module": "esnext",

// 如何处理模块

"moduleResolution": "node",

// 编译输出目标 ES 版本

"target": "es5",

// 容许从没有设置默认导出的模块中默认导入

"allowSyntheticDefaultImports": true,

// 将每一个文件做为单独的模块

"isolatedModules": false,

// 启用装饰器

"experimentalDecorators": true,

// 启用设计类型元数据(用于反射)

"emitDecoratorMetadata": true,

// 在表达式和声明上有隐含的any类型时报错

"noImplicitAny": false,

// 不是函数的全部返回路径都有返回值时报错。

"noImplicitReturns": true,

// 从 tslib 导入外部帮助库: 好比__extends,__rest等

"importHelpers": true,

// 编译过程当中打印文件名

"listFiles": true,

// 移除注释

"removeComments": true,

"suppressImplicitAnyIndexErrors": true,

// 容许编译javascript文件

"allowJs": true,

// 解析非相对模块名的基准目录

"baseUrl": "./",

// 指定特殊模块的路径

"paths": {

"jquery": [

"node_modules/jquery/dist/jquery"

]

},

// 编译过程当中须要引入的库文件的列表

"lib": [

"dom",

"es2015",

"es2015.promise"

]

}

}

复制代码

四、添加 tslint.json

在根路径下建立tslint.json文件,就是 引入 ts 的 standard 规范

{

"defaultSeverity": "error",

"extends": "tslint-config-standard",

"globals": {

"require": true

},

"rules": {

"space-before-function-paren": false,

"whitespace": [false],

"no-consecutive-blank-lines": false,

"no-angle-bracket-type-assertion": false,

"no-empty-character-class": false

}

}

复制代码

五、让 ts 识别 .vue

因为 TypeScript 默认并不支持 *.vue 后缀的文件,因此在 vue 项目中引入的时候须要建立一个 vue-shim.d.ts 文件,放在项目项目对应使用目录下,例如 src/vue-shim.d.ts

// 意思是告诉 TypeScript *.vue 后缀的文件能够交给 vue 模块来处理

import Vue from "vue";

import lodash from "lodash";

// 重要***

declare module '*.vue' {

export default Vue

}

declare module 'vue/types/vue' {

interface Vue {

$Message: any,

$Modal: any

}

}

declare global {

const _: typeof lodash

}

复制代码

而在代码中导入 *.vue 文件的时候,须要写上 .vue 后缀。缘由仍是由于 TypeScript 默认只识别 *.ts 文件,不识别 *.vue 文件

import HelloWorld from '@/components/HelloWorld.vue'

六、改造 .vue 文件

在这以前先让咱们了解一下所须要的插件(下面的内容须要掌握es7的装饰器, 就是下面使用的@符号)

vue-class-component

vue-class-component 对 Vue 组件进行了一层封装,让 Vue 组件语法在结合了 TypeScript 语法以后更加扁平化:

msg: {{ msg }}

computed msg: {{ computedMsg }}

Greet

import Vue from 'vue'

import Component from 'vue-class-component'

@Component

export default class App extends Vue {

// 初始化数据

msg = 123

// 声明周期钩子

mounted () {

this.greet()

}

// 计算属性

get computedMsg () {

return 'computed ' + this.msg

}

// 方法

greet () {

alert('greeting: ' + this.msg)

}

}

复制代码

上面的代码跟下面的代码做用是同样的

export default {

data () {

return {

msg: 123

}

}

// 声明周期钩子

mounted () {

this.greet()

}

// 计算属性

computed: {

computedMsg () {

return 'computed ' + this.msg

}

}

// 方法

methods: {

greet () {

alert('greeting: ' + this.msg)

}

}

}

复制代码

vue-property-decorator

vue-property-decorator 是在 vue-class-component 上加强了更多的结合 Vue 特性的装饰器,新增了这 7 个装饰器:

@Emit

@Inject

@Model

@Prop

@Provide

@Watch

@Component (从 vue-class-component 继承)

在这里列举几个经常使用的@Prop/@Watch/@Component, 更多信息,详见官方文档

import { Component, Emit, Inject, Model, Prop, Provide, Vue, Watch } from 'vue-property-decorator'

@Component

export class MyComponent extends Vue {

@Prop()

propA: number = 1

@Prop({ default: 'default value' })

propB: string

@Prop([String, Boolean])

propC: string | boolean

@Prop({ type: null })

propD: any

@Watch('child')

onChildChanged(val: string, oldVal: string) { }

}

复制代码

上面的代码至关于:

export default {

props: {

checked: Boolean,

propA: Number,

propB: {

type: String,

default: 'default value'

},

propC: [String, Boolean],

propD: { type: null }

}

methods: {

onChildChanged(val, oldVal) { }

},

watch: {

'child': {

handler: 'onChildChanged',

immediate: false,

deep: false

}

}

}

复制代码

开始修改App.vue文件

在script 标签上加上 lang="ts", 意思是让webpack将这段代码识别为typescript 而非javascript

修改vue组件的构造方式,详见官方

用vue-property-decorator语法改造以前代码

以下:

import Vue from 'vue'

import Component from 'vue-class-component'

@Component({})

export default class App extends Vue {}

复制代码

开始修改HelloWorld.vue

以下:

{{ message }}

Essential Links

Click!

import Vue from 'vue'

import Component from 'vue-class-component'

@Component({

// 全部的组件选项均可以放在这里

})

export default class HelloWorld extends Vue {

// 初始数据能够直接声明为实例的属性

message: string = 'Welcome to Your Vue.js + TypeScript App'

// 组件方法也能够直接声明为实例的方法

onClick (): void {

console.log(this.message)

console.log(_)

}

}

复制代码

至此,运行npm run dev npm run build 都能正常跑起来了

四、进阶TS配置

一、支持es6 / es7

在 tsconfig.json中,添加对es6 / es7的支持,更多的配置请见tsconfig - 编译选项

"lib": [

"dom",

"es5",

"es6",

"es7",

"es2015.promise"

]

复制代码

二、让 vue 识别全局方法/变量

在建立的 src/vue-shim.d.ts文件中,增长以下代码

// 声明全局方法

declare module 'vue/types/vue' {

interface Vue {

$Message: any,

$Modal: any

}

}

复制代码

这样,以后再使用this.$message()的话就不会报错了

三、支持 ProvidePlugin 的全局变量,好比 lodash 的 _

若是咱们在项目中有使用 jquery,lodash 这样的工具库的时候,确定不但愿在全部用到的地方都import _ from ‘lodash’

那咱们就来配置一下:

首先仍是在webpack.base.conf.js 中添加一个插件、并把这个 vendor拉出来

entry: {

app: './src/main.ts',

vendor: [

"lodash"

]

}

plugins: [

new webpack.ProvidePlugin({

_: 'lodash'

})

]

复制代码

上面的意思是,当模块使用这些变量的时候wepback会自动加载

而后,你须要告诉eslint这个 _ 是全局的

在.eslintrc.js中添加

globals: {

_: true

},

复制代码

接下来,你还须要告诉ts这个 _ 是全局的

在vue-shim.d.ts

declare global {

const _: typeof lodash

}

复制代码

这样,在其余地方就能够用_直接调用啦

四、配置 vuex

# 安装依赖

npm i vuex vuex-class --save

复制代码

vuex:在 vue 中集中管理应用状态

vuex-class :在 vue-class-component 写法中 绑定 vuex

最后

到这里就结束了最基础的配置啦,但愿能够帮到你噢!

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值