├── .browserslistrc ├── src ├── a.png ├── b.jpg ├── typings │ └── images.d.ts ├── App.tsx ├── shims-vue.d.ts └── main.ts ├── .eslintignore ├── README.md ├── .gitignore ├── public └── index.html ├── postcss.config.js ├── .eslintrc.js ├── tsconfig.json ├── babel.config.js ├── package.json ├── webpack.dev.config.js └── webpack.prod.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions -------------------------------------------------------------------------------- /src/a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bendajun/webpack-vue-cli/HEAD/src/a.png -------------------------------------------------------------------------------- /src/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bendajun/webpack-vue-cli/HEAD/src/b.jpg -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | public/* 3 | dist/* 4 | webpack.dev.config.js 5 | webpack.prod.config.js -------------------------------------------------------------------------------- /src/typings/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' 2 | declare module '*.png' 3 | declare module '*.jpg' 4 | declare module '*.jpeg' 5 | declare module '*.gif' 6 | declare module '*.bmp' 7 | declare module '*.tiff' 8 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { defineComponent } from 'vue'; 3 | 4 | export default defineComponent({ 5 | render: function() { 6 | const a = 12345; 7 | const b: number = a; 8 | return
11 |
12 |
13 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/no-var-requires
2 | const autoprefixer = require('autoprefixer');
3 | module.exports = {
4 | plugins: [
5 | autoprefixer(), // 添加浏览器前缀
6 | /* require("cssnano")({
7 | preset: ['default', {
8 | mergeLonghand: false,
9 | cssDeclarationSorter: false
10 | }]
11 | }) */
12 | ]
13 | };
14 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: [
7 | 'plugin:vue/vue3-essential',
8 | '@vue/standard',
9 | '@vue/typescript/recommended',
10 | ],
11 | parserOptions: {
12 | ecmaVersion: 2020
13 | },
14 | rules: {
15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
17 | 'space-before-function-paren': ['error', 'never'], // 函数名后面是否需要个空格
18 | 'comma-dangle': ['off', 'always'], // 是否可以在最后一项添加逗号
19 | semi: ['warn', 'always'],
20 | quotes: ['warn', 'single']
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | // 编译选项
4 | "target": "esnext", // 编译输出目标ES版本
5 | "module": "esnext", // 采用的模块系统
6 | "strict": true, // 以严格模式解析
7 | "jsx": "preserve",
8 | "importHelpers": true,
9 | "moduleResolution": "node", // 如何处理模块
10 | "experimentalDecorators": true, // 启用装饰器
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入
13 | "strictPropertyInitialization": false, // 定义一个变量就必须给它一个初始值
14 | "allowJs": true, // 允许编辑javascript文件
15 | "sourceMap": true, // 是否包含可以用于 debug 的 sourceMap
16 | "noImplicitThis": false, // 忽略 this 的类型检查, Raise error on this expressions with an implied any type.
17 | "baseUrl": ".", // 解析非相对模块名的基准目录
18 | "pretty": true, // 给错误和消息设置样式,使用颜色和上下文
19 | "types": [ // 设置引入的定义文件
20 | "webpack-env",
21 | ],
22 | "paths": {
23 | "@/*": [
24 | "src/*"
25 | ]
26 | },
27 | "lib": [
28 | // 编译过程中需要引入的库文件的列表
29 | "esnext",
30 | "dom",
31 | "dom.iterable",
32 | "scripthost"
33 | ]
34 | },
35 | "include": [
36 | // ts 管理的文件
37 | "src/**/*.ts",
38 | "src/**/*.tsx",
39 | "src/**/*.vue",
40 | ".src//typings/images.d.ts",
41 | ],
42 | "exclude": [ // ts 排除的文件,不编译这些目录里的文件
43 | "node_modules"
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | // 在babel7.4.0之后所有的polyfill操作都依赖core-js
2 | /**
3 | * 用preset-env来转换语法和polyfill,
4 | * 然后再利用@babel/plugin-transform-runtime来引入helpers跟generator做到代码重复利用
5 | */
6 | module.exports = {
7 | presets: [ // 预设,可以理解为一系列封装好的插件的集合
8 | // '@vue/babel-preset-jsx', // 让vue支持jsx跟tsx,但是vue3不能使用这个预设,需使用@vue/babel-plugin-jsx这个插件
9 | [
10 | '@babel/preset-env', // 添加preset-env预设做语法转换,preset-env能将最新的语法转换为ecmascript5的写法
11 | {
12 | corejs: 3, // corejs版本,core-js@3废弃了babel-polyfill,实现了完全无污染的API转译
13 | useBuiltIns: 'usage', // 不需要手动在代码里写import‘@babel/polyfilll’,打包时会自动根据实际代码的使用情况,结合 .browserslistrc 引入代码里实际会用到 polyfilll部分模块
14 | }
15 | ]
16 | ],
17 | plugins: [ // 插件,使用插件去对js做对应的功能
18 | '@vue/babel-plugin-jsx', // Vue 3 Babel JSX 插件, 如果要在vue3中使用render函数,必须使用这个插件,而不是@vue/babel-preset-jsx,这个坑我踩了几天,不然会出现h is not defined的错误。https://github.com/vuejs/jsx-next/blob/dev/packages/babel-plugin-jsx/README-zh_CN.md
19 | // @babel/plugin-proposal-decorators 和 @babel/plugin-proposal-class-properties 让项目中可以使用装饰器写法,但是Vue3中一般也不使用了
20 | ['@babel/plugin-proposal-decorators', { // 装饰器插件
21 | legacy: true
22 | }],
23 | '@babel/plugin-proposal-class-properties', // 类属性插件
24 | [
25 | '@babel/plugin-transform-runtime', // 利用runtime做helpers跟regenerator设置
26 | {
27 | corejs: false,
28 | helpers: true,
29 | useESModules: false,
30 | regenerator: true,
31 | absoluteRuntime: './node_modules'
32 | }
33 | ]
34 | ]
35 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cli-d-component",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "dev": "webpack serve --config webpack.dev.config.js --progress",
7 | "build": "webpack --config webpack.prod.config.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "author": "dudapeng",
11 | "license": "ISC",
12 | "description": "vue webpack components",
13 | "devDependencies": {
14 | "@babel/core": "^7.12.10",
15 | "@babel/plugin-proposal-decorators": "^7.12.1",
16 | "@babel/plugin-transform-runtime": "^7.12.10",
17 | "@babel/preset-env": "^7.12.10",
18 | "@typescript-eslint/eslint-plugin": "^4.10.0",
19 | "@typescript-eslint/parser": "^4.10.0",
20 | "@vue/babel-plugin-jsx": "^1.0.0-rc.5",
21 | "@vue/babel-preset-jsx": "^1.2.4",
22 | "@vue/compiler-sfc": "^3.0.0",
23 | "@vue/eslint-config-standard": "^6.0.0",
24 | "@vue/eslint-config-typescript": "^7.0.0",
25 | "@webpack-cli/serve": "^1.1.0",
26 | "autoprefixer": "^8.6.5",
27 | "babel-loader": "^8.2.2",
28 | "clean-webpack-plugin": "^3.0.0",
29 | "core-js": "^3.8.1",
30 | "css-loader": "^5.0.1",
31 | "cssnano": "^4.1.10",
32 | "eslint": "^7.15.0",
33 | "eslint-loader": "^4.0.2",
34 | "eslint-plugin-import": "^2.22.1",
35 | "eslint-plugin-node": "^11.1.0",
36 | "eslint-plugin-promise": "^4.2.1",
37 | "eslint-plugin-standard": "^5.0.0",
38 | "eslint-plugin-vue": "^7.2.0",
39 | "file-loader": "^6.2.0",
40 | "fork-ts-checker-webpack-plugin": "^6.0.4",
41 | "html-loader": "^1.3.2",
42 | "html-webpack-plugin": "^4.5.0",
43 | "mini-css-extract-plugin": "^1.3.3",
44 | "postcss-loader": "^4.1.0",
45 | "sass": "^1.30.0",
46 | "sass-loader": "^10.1.0",
47 | "style-loader": "^2.0.0",
48 | "svg-sprite-loader": "^5.2.1",
49 | "svgo": "^1.3.2",
50 | "svgo-loader": "^2.2.1",
51 | "ts-loader": "^8.0.11",
52 | "typescript": "^4.1.2",
53 | "url-loader": "^4.1.1",
54 | "vue-loader": "^16.0.0-beta.7",
55 | "webpack": "^5.10.3",
56 | "webpack-chain": "^6.5.1",
57 | "webpack-cli": "^4.2.0",
58 | "webpack-dev-server": "^3.11.0"
59 | },
60 | "dependencies": {
61 | "vue": "^3.0.0",
62 | "vue-class-component": "^7.2.6",
63 | "vue-property-decorator": "^9.1.2"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const Config = require('webpack-chain');
4 | const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
5 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
6 |
7 | const config = new Config();
8 | const publicPath = '/';
9 | // webpack-cli4 + webpack5 启动devServe是webpack serve了,而不是webpack-dev-server
10 | // webpack5 内部实现了cache-loader的效果
11 |
12 | config
13 | .target('web') // webpack5需要加这个,不然热更新不会手动刷新页面
14 | .mode('development')
15 | .context(path.resolve(__dirname, '.')) // 指定项目根目录
16 | .entry('app') // 指定入口文件名称为app
17 | .add('./src/main.ts') // 入口文件
18 | .end()
19 | .output
20 | .path(path.join(__dirname, './dist')) // webpack打包输出的文件夹
21 | .filename('js/[name].[contenthash:10].js') // 打包出来的bundle名称为[name].[contenthash:10].js
22 | .publicPath(publicPath) // 资源文件前缀
23 | .end()
24 | .resolve
25 | .extensions
26 | .add('.js').add('.jsx').add('.ts').add('.tsx').add('.vue') // 使用着希望文件时,导入时可以省略后缀
27 | .end()
28 | .alias // 设置别名
29 | .set('@', path.resolve(__dirname, './src'))
30 | .set('vue$', 'vue/dist/vue.runtime.esm-bundler.js') // 开发环境使用这个vue.js,参照vue-cli的vue3项目
31 | .end()
32 | .end()
33 | .module
34 | .rule('js')
35 | .test(/\.m?jsx?$/) // 对mjs、mjsx、js、jsx文件进行babel配置
36 | .exclude // 排除node_modules
37 | .add(filepath => /node_modules/.test(filepath))
38 | .end()
39 | .use('babel-loader')
40 | .loader('babel-loader')
41 | .end()
42 | .end()
43 | .rule('ts') // rule起的名字只是语义化,方便理解,和导出配置或者修改配置时对应
44 | .test(/\.tsx?$/) // 匹配处理后缀是ts或者tsx结尾的文件
45 | .use('babel-loader')
46 | .loader('babel-loader')
47 | .end()
48 | .use('ts-loader') // use也是语义化的名字,同rule
49 | .loader('ts-loader') // 这里才是使用ts-loader去处理匹配的文件
50 | .options({ // 这里对ts-loader进行相关的配置, 创建个tsconfig.json文件,默认会读取和使用这个文件
51 | transpileOnly: true, // 开启时: 编译器仅做语言转换不做类型检查,加快编译速度,但是静态类型检查中获得的许多好处将丢失。所以结合插件ForkTsCheckerWebpackPlugin用于新建进程执行类型检查,为此你需要关闭ts-loader自身的类型检查功能,即设置transpileOnly为true。
52 | appendTsSuffixTo: ['\\.vue$'], // 给vue文件添加个.ts或.tsx后缀,vue单文件组件中假如使用了 lang="ts", ts-loader需要配置 appendTsSuffixTo: [/\.vue$/],用来给 .vue文件添加个 .ts后缀用于编译,因为tsc不知道如何处理. vue文件结尾的文件
53 | happyPackMode: false,
54 | })
55 | .end()
56 | .end()
57 | .rule('vue')
58 | .test(/\.vue$/) // 匹配处理.vue后缀文件
59 | .use('vue-loader')
60 | .loader('vue-loader')
61 | .end()
62 | .end()
63 | .rule('sass')
64 | .test(/\.(sass|scss)$/) // 处理sass和scss文件
65 | .use('style-loader') // 开发环境用:style-loader 是将js中的css文件提取出来,放在style标签中,style-loader内部实现了热模块替换(HMR,一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块))
66 | .loader('style-loader')
67 | .end()
68 | .use("css-loader") // 处理css
69 | .loader("css-loader")
70 | .end()
71 | /**
72 | * autofixer是postcss的功能插件,主要是给css中的一些属性添加-webkit-这种前缀做兼容的,postcss-loader则是webpack的loader组件,主要作用是webpack在读取css模块的时候调用postcss和postcss的插件对css内容做兼容性处理的。
73 | * postcss-loader配置options的过程实际上是为postcss配置需要的插件
74 | */
75 | .use('postcss-loader') // 兼容性处理css
76 | .loader('postcss-loader')
77 | .options({
78 | postcssOptions: { // 指定配置文件,如果不指定的话其实是默认去根路径找postcss.config.js这个文件的,指定的好处就是可以指定特定的文件名
79 | config: path.resolve(__dirname, './postcss.config.js')
80 | }
81 | })
82 | .end()
83 | .use('sass-loader') // 先将sass语法转换为css语法
84 | .loader('sass-loader')
85 | .end()
86 | .end()
87 | .rule('eslint')
88 | .exclude
89 | .add(/node_modules/)
90 | .end()
91 | .test(/\.(vue|(j|t)sx?)$/)// 处理.vue、.js、.jsx、.ts、.tsx文件
92 | .use('eslint-loader')
93 | .loader(require.resolve('eslint-loader'))
94 | .options({
95 | emitWarning: false, // 出现警告是否终止webpack编译
96 | emitError: true,
97 | })
98 | .end()
99 | .end()
100 | .rule('images') // 处理png|jpe?g|gif|webp图片 处理图片需要安装 url-loader file-loader,安装file-loader的原因是url-loader是依赖它
101 | .test(/\.(png|jpe?g|gif|webp)$/)
102 | .use('url-loader')
103 | .loader('url-loader')
104 | .options({
105 | limit: 8 * 1024, // 当图片大小小于8kb,就会被处理为base64位字符串,优点:减少请求数量(减轻服务器压力),缺点:图片体积会更大(文件加载速度更慢)
106 | name: '[hash:10].[ext]', // [ext]取文件原来扩展名
107 | outputPath: 'imgs', // 放在img文件夹下
108 | })
109 | .end()
110 | .end()
111 | .rule('icons')
112 | .test(/\.svg$/) // 处理svg图片
113 | .include
114 | .add(path.resolve(__dirname, './src/icons')) // 处理的svg放在此路径下
115 | .end()
116 | .use('svg-sprite-loader')
117 | .loader('svg-sprite-loader')
118 | .options({
119 | symbolId: 'icon-[name]'
120 | })
121 | .end()
122 | .use('svgo-loader')
123 | .loader('svgo-loader')
124 | .end()
125 | .end()
126 | .rule('html') // html-loader是专门处理html文件中的img图片(负责引入img,从而能被url-loader进行处理)
127 | .test(/\.html$/)
128 | .use('html-loader')
129 | .loader('html-loader')
130 | .end()
131 | .end()
132 | .rule('other') // 打包其他资源(除了html/js/css等资源以外的资源),将这些资源不压缩,不转换统一打包过去,相当于复制过去
133 | .test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/)
134 | .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
135 | .use('file-loader')
136 | .loader('file-loader') // 用file-loader来处理这些其他资源,可以原封不动的打包过去
137 | .options({
138 | name: '[hash:10].[ext]',
139 | })
140 | .end()
141 | .end()
142 | config
143 | .plugin('fork-ts-checker')
144 | .use(ForkTsCheckerWebpackPlugin, [{ // 插件ForkTsCheckerWebpackPlugin用于新建进程执行类型检查,为此你需要关闭ts-loader自身的类型检查功能,即设置transpileOnly为true
145 | eslint: { // 这个是结合eslint使用时的
146 | files: './src/**/*.{ts,tsx,js,jsx}' // required - same as command `eslint ./src/**/*.{ts,tsx,js,jsx} --ext .ts,.tsx,.js,.jsx`
147 | },
148 | typescript: {
149 | extensions: {
150 | vue: {
151 | enabled: true, // 如果为true,则启用Vue单个文件组件支持。
152 | compiler: '@vue/compiler-sfc' // 默认值是vue-template-compiler,不适用于vue3,用于解析.vue文件的编译器的程序包名称
153 | }
154 | },
155 | diagnosticOptions: {
156 | semantic: true,
157 | syntactic: false
158 | }
159 | }
160 | }])
161 | .end()
162 | .plugin('vue-loader-plugin') // vue-loader必须要添加vue-loader-plugin
163 | .use(require('vue-loader').VueLoaderPlugin, [])// 是将你定义过的其它规则复制并应用到 .vue 文件里相应语言的块。例如,如果你有一条匹配 /\.js$/ 的规则,那么它会应用到 .vue 文件里的