Browse Source

KERNEL-6234 refactor: starter支持ts和es写法

feature
youki 4 years ago
parent
commit
610a342a82
  1. 4
      .eslintignore
  2. 171
      .eslintrc
  3. 1
      .gitignore
  4. 1
      .npmrc
  5. 121
      Gruntfile.js
  6. 9
      README.md
  7. 1
      babel.config.js
  8. 51
      package.json
  9. 1
      src/core/javascript/decorator.js
  10. 3
      src/core/typescript/decorator.ts
  11. 16
      src/css/header/header.css
  12. 0
      src/css/index.css
  13. 14
      src/css/list/list.css
  14. 6
      src/css/main.css
  15. 0
      src/css/nav/nav.css
  16. 12
      src/index.js
  17. 2
      src/index.less
  18. 83
      src/modules/header/header.js
  19. 90
      src/modules/list/list.js
  20. 101
      src/modules/list/list.ts
  21. 116
      src/modules/main.js
  22. 10
      src/types/globals.d.ts
  23. 7
      tsconfig.json
  24. 9
      webpack/dirs.js
  25. 63
      webpack/webpack.common.js
  26. 53
      webpack/webpack.dev.js
  27. 60
      webpack/webpack.prod.js

4
.eslintignore

@ -0,0 +1,4 @@
types
node_modules/
dist/
assets/

171
.eslintrc

@ -1,171 +1,8 @@
{
"extends": "eslint:recommended",
"rules": {
// 声明
"no-use-before-define": "error",
//禁止定义前使用
// 对象
"no-dupe-keys": "error",
// 禁止在对象字面量中出现重复的键
"quote-props": [
"error",
"as-needed"
],
// 对象属性只在需要的时候加引号
// 字符串
"quotes": [
"error",
"double",
{
"allowTemplateLiterals": true
"extends": "plugin:@fui/typescript",
"parserOptions": {
"ecmaFeatures": {
"legacyDecorators": true
}
],
// 字符串开头和结束使用双引号
"no-useless-concat": "error",
// 禁止没有必要的字符拼接
"no-useless-escape": "error",
// 禁用不必要的转义
// 函数
"no-dupe-args": "error",
// 禁止在 function 定义中出现重复的参数
"space-before-function-paren": "error",
// 函数括号前必须要有空格
// 变量
"no-undef": "error",
// 禁止使用未声明的变量
// 比较运算符 & 相等运算符
"eqeqeq": "error",
// 使用 === 和 !== 代替 == 和 !=
"no-unneeded-ternary": "error",
//禁止可以在有更简单的可替代的表达式时使用三元操作符
// 条件
"default-case": "error",
// 要求 Switch 语句中有 Default 分支
"no-else-return": "error",
// 如果 if 块中包含了一个 return 语句,else 块就成了多余的了。可以将其内容移至块外
// 代码块
"brace-style": [
"error",
"1tbs",
{
"allowSingleLine": true
}
],
// 代码块左括号紧跟上一行结束
"curly": [
"error",
"multi-line"
],
// if、else if、else、for、while强制使用大括号,但允许在单行中省略大括号
// 注释
"spaced-comment": "error",
// 注释前有空格
// 空白
"indent": [
"error",
4,
{
"SwitchCase": 1
}
],
// 缩进控制4空格
"no-mixed-spaces-and-tabs": "error",
// 禁止使用 空格 和 tab 混合缩进
"space-before-blocks": [
"error",
"always"
],
// 语句块之前的需要有空格
"space-infix-ops": [
"error",
{
"int32Hint": false
}
],
// 要求中缀操作符周围有空格,设置 int32Hint 选项为 true (默认 false) 允许 a|0 不带空格
"no-trailing-spaces": [
"error",
{
"skipBlankLines": true
}
],
// 禁用行尾空格
"key-spacing": [
"error",
{
"afterColon": true
}
],
// 要求在对象字面量的冒号和值之间存在至少有一个空格
// 逗号
"comma-style": "error",
// 逗号必须放在行末
"comma-dangle": [
"error",
"never"
],
// 多行对象字面量中要求不要拖尾逗号
"comma-spacing": [
"error",
{
"before": false,
"after": true
}
],
//在变量声明、数组字面量、对象字面量、函数参数 和 序列中禁止在逗号前使用空格,要求在逗号后使用一个或多个空格
// 分号
"semi": "error",
//不得省略语句结束的分号
"semi-spacing": [
"error",
{
"before": false,
"after": true
}
],
//禁止分号周围的空格
"no-extra-semi": "error",
// 禁用不必要的分号
// 类型转换
"no-extra-boolean-cast": "error",
// 禁止不必要的布尔类型转换
// 其他最佳实践或规范
"no-unexpected-multiline": "error",
// 禁止使用令人困惑的多行表达式
"no-unreachable": "error",
// 禁止在 return、throw、continue 和 break 语句后出现不可达代码
"valid-typeof": "error",
// 强制 typeof 表达式与有效的字符串进行比较
"no-new-wrappers": "error"
// 禁止通过 new 操作符使用 String、Number 和 Boolean
},
"globals": {
"window": true,
"BI": true,
"BICst": true,
"Data": true,
"Fix": true,
"module": true,
"describe": true,
"it": true,
"expect": true,
"Dec": true
}
}

1
.gitignore vendored

@ -49,3 +49,4 @@ crashlytics-build.properties
/node_modules/
package-lock.json
yarn.lock
/dist

1
.npmrc

@ -0,0 +1 @@
@fui:registry=https://npm.fineres.com/

121
Gruntfile.js

@ -1,121 +0,0 @@
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
concat: {
options: {
separator: ""
},
bundleJs: {
src: [
"src/modules/**/*.js",
"src/index.js"
],
dest: "dist/bundle.js"
},
bundleCss: {
src: ["src/css/**/*.css"],
dest: "dist/bundle.css"
}
},
less: {
main: {
expand: true,
cwd: "src/modules",
src: ["**/*.less"],
dest: "src/css/",
ext: ".css"
},
dev: {
options: {
compress: true,
yuicompress: false
}
}
},
uglify: {
options: {
banner:
"/*! <%= pkg.name %> <%= grunt.template.today(\"dd-mm-yyyy\") %> */\n"
},
dist: {
files: {
"dist/bundle.min.js": ["<%= concat.bundleJs.dest %>"]
}
}
},
cssmin: {
bundleCss: {
src: "<%= concat.bundleCss.dest %>",
dest: "dist/bundle.min.css"
}
},
jshint: {
files: ["src/**/*.js"],
options: {
globals: {
$: true,
jQuery: true,
console: true,
module: true,
document: true
},
browser: true,
expr: true
}
},
watch: {
scripts: {
files: ["src/**/*.js", "src/**/*.less"],
tasks: ["less", "concat"],
options: {
spanw: true,
interrupt: true
}
},
livereload: {
options: {
livereload: "<%= connect.options.livereload %>"
},
files: ["src/**/*.js", "src/**/*.less"]
}
},
connect: {
options: {
port: 9000,
open: true,
livereload: 35799,
// Change this to '0.0.0.0' to access the server from outside
hostname: "localhost"
},
server: {
options: {
port: 9009,
base: "./"
}
}
}
});
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.loadNpmTasks("grunt-contrib-less");
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-concat");
grunt.loadNpmTasks("grunt-contrib-cssmin");
grunt.loadNpmTasks("grunt-contrib-connect");
grunt.registerTask("default", [
"jshint",
"less",
"concat",
"connect",
"watch"
]);
grunt.registerTask("min", ["less", "concat", "uglify", "cssmin"]);
};

9
README.md

@ -3,9 +3,14 @@
## 安装运行
`git clone --recursive https://git.fanruan.com/dailer/FineUI-Start.git`
`npm install`
## 安装依赖
`yarn install`
`npm run grunt`
## 打开dev模式
`yarn start`
## 打包
`yarn build`
## 示例效果
![](./screenshorts/todolist.gif)

1
babel.config.js

@ -0,0 +1 @@
module.exports = require('@fui/babel-preset-fineui').configs.ie8;

51
package.json

@ -7,27 +7,40 @@
"fineui": "^2.0.0"
},
"devDependencies": {
"chai": "4.1.2",
"eslint": "4.12.0",
"eslint-plugin-prettier": "2.3.1",
"express": "4.15.2",
"grunt": "1.0.1",
"grunt-contrib-concat": "1.0.1",
"grunt-contrib-connect": "1.0.2",
"grunt-contrib-cssmin": "1.0.1",
"grunt-contrib-jshint": "1.0.0",
"grunt-contrib-less": "1.4.1",
"grunt-contrib-uglify": "1.0.1",
"grunt-contrib-watch": "1.0.0",
"lodash": "4.17.10",
"mocha": "4.0.1",
"open": "0.0.5",
"prettier": "1.8.2"
"@fui/babel-preset-fineui": "^1.0.0",
"@fui/typescript-configs": "^1.0.1",
"@fui/eslint-plugin": "^1.0.7",
"@types/jest": "24.0.11",
"typescript": "3.9.2",
"fork-ts-checker-webpack-plugin": "1.4.3",
"autoprefixer": "9.6.1",
"babel-loader": "8.0.6",
"cross-env": "6.0.0",
"css-loader": "3.0.0",
"html-webpack-plugin": "3.2.0",
"jest": "24.7.1",
"jest-css-modules-transform": "2.5.0",
"jest-environment-jsdom": "24.7.1",
"jest-snapshot": "23.6.0",
"less": "^3.11.3",
"less-loader": "5.0.0",
"mini-css-extract-plugin": "0.7.0",
"npm-run-all": "4.1.5",
"optimize-css-assets-webpack-plugin": "5.0.3",
"postcss-loader": "3.0.0",
"postcss-simple-vars": "5.0.2",
"source-map-loader": "0.2.4",
"style-loader": "0.23.1",
"uglifyjs-webpack-plugin": "2.2.0",
"webpack": "4.35.2",
"webpack-cli": "3.3.5",
"webpack-dev-server": "3.7.2",
"webpack-merge": "4.2.1"
},
"scripts": {
"grunt": "grunt",
"uglify": "grunt min",
"eslint": "eslint src --fix"
"start": "webpack-dev-server -p --progress --host 127.0.0.1 --config=webpack/webpack.dev.js --mode development",
"build": "webpack -p --progress --config=webpack/webpack.prod.js --mode production",
"test": "jest"
},
"author": "",
"license": "MIT"

1
src/core/javascript/decorator.js

@ -0,0 +1 @@
export const { shortcut, Model, model, store } = BI.Decorators;

3
src/core/typescript/decorator.ts

@ -0,0 +1,3 @@
export const { shortcut, Model, model, store } = BI.Decorators;
export type Constructor<T> = new(...args: any[]) => T;

16
src/css/header/header.css

@ -1,16 +0,0 @@
/**
列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求
*/
.my-todolist-header {
background-color: #3d4d66;
}
.my-todolist-header .my-todolist-title {
font-size: 22px;
color: #FFF;
}
.my-todolist-header .my-todolist-header-editor {
background-color: #FFF;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}

0
src/css/index.css

14
src/css/list/list.css

@ -1,14 +0,0 @@
/**
列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius方法等.请选择性使用.不强制要求
*/
.my-todolist-list .my-todolist-list-text {
font-size: 16px;
font-weight: bold;
}
.my-todolist-list .my-todolist-list-count-container {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
background-color: #3d4d66;
color: #ffffff;
}

6
src/css/main.css

@ -1,6 +0,0 @@
/**
列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求
*/
.my-todolist-background {
background-color: #f7f8fa;
}

0
src/css/nav/nav.css

12
src/index.js

@ -1,7 +1,7 @@
!(function () {
// 将todolist组件挂载到#wrapper上.
BI.createWidget({
type: "my.todolist",
import { ToDoList } from "./modules/main";
// 将todolist组件挂载到#wrapper上.
BI.createWidget({
type: ToDoList.xtype,
element: "#wrapper"
});
})();
});

2
src/index.less

@ -1,4 +1,4 @@
@import "../fineui/src/less/index";
@import "../node_modules/fineui/src/less/index";
@fontUrl: 'font/'; //字体存放路径
@imageUrl: 'images/1x/'; //图片的基本地址

83
src/modules/header/header.js

@ -1,42 +1,50 @@
!(function() {
/**
import { shortcut } from "../../core/javascript/decorator";
import "./header.less";
/**
* 顶部组件,提供输入框添加todo项目
* 布局: bi.horizontal_auto 实现水平居中. bi.left_right_vertical_adapt 实现标题是输入框的靠左靠右垂直居中
*/
var ToDoListHeader = BI.inherit(BI.Widget, {
@shortcut()
export class ToDoListHeader extends BI.Widget {
static xtype = "my.todolist.header";
static EVENT_ADD = "EVENT_ADD";
props: {
props = {
// 指定组件的className
baseCls: "my-todolist-header"
},
baseCls: "my-todolist-header",
}
render() {
const { height } = this.options;
render: function() {
var self = this, o = this.options;
return {
type: "bi.horizontal_auto", // 水平居中布局
items: [
{
// 水平居中布局
type: BI.HorizontalAutoLayout.xtype,
items: [{
el: {
type: "bi.left_right_vertical_adapt", // 左右垂直居中布局
// 左右垂直居中布局
type: BI.LeftRightVerticalAdaptLayout.xtype,
width: 600,
height: o.height,
height: 40,
items: {
left: [
{
el: {
type: "bi.label",
type: BI.Label.xtype,
cls: "my-todolist-title",
text: "FineUI ToDoList",
height: o.height
}
}
height,
},
},
],
right: [
{
el: {
type: "bi.editor",
ref: function(_ref) {
self.editor = _ref;
type: BI.Editor.xtype,
ref: _ref => {
this.editor = _ref;
},
allowBlank: true,
cls: "my-todolist-header-editor",
@ -44,27 +52,20 @@
width: 300,
height: 24,
listeners: [
{ // 监听bi.editor 组件的"EVENT_ENTER"事件(即敲回车),触发事件ToDoListHeader.EVENT_ADD事件并将输入框值置
{ // 监听bi.editor 组件的"EVENT_ENTER"事件(即敲回车),触发事件ToDoListHeader.EVENT_ADD事件并将输入框值置
eventName: "EVENT_ENTER",
action: function() {
// 注意:在这里this指向的是bi.editor的实例.通过bi.editor的getValue()方法获取输入框输入值.
self.fireEvent(ToDoListHeader.EVENT_ADD, this.getValue());
self.editor.setValue("");
}
}
]
}
}
]
}
}
}
]
action: () => {
this.fireEvent(ToDoListHeader.EVENT_ADD, this.editor.getValue());
this.editor.setValue("");
},
},
],
},
},
],
},
},
}],
};
}
});
ToDoListHeader.EVENT_ADD = "EVENT_ADD";
BI.shortcut("my.todolist.header", ToDoListHeader);
})();
}

90
src/modules/list/list.js

@ -1,90 +0,0 @@
!(function() {
/**
* todo项列表
*
*/
var List = BI.inherit(BI.Widget, {
props: {
// 指定组件的className
baseCls: "my-todolist-list",
text: "正在进行"
},
render: function() {
var self = this, o = this.options;
return {
type: "bi.vertical",
items: [
{
el: {
type: "bi.vertical_adapt",
height: 40,
items: [
{
type: "bi.label",
cls: "my-todolist-list-text",
textAlign: "left",
text: o.text,
width: 580
}, {
type: "bi.center_adapt",
cls: "my-todolist-list-count-container",
width: 20,
height: 20,
items: [
{
el: {
type: "bi.label",
ref: function(_ref) {
self.count = _ref;
},
text: "0"
}
}
]
}
]
}
}, { // 用bi.vertical布局作为列表项的容器.
type: "bi.vertical",
vgap: 10,
ref: function(_ref) {
self.list = _ref;
},
items: this._createItems(o.items)
}
]
};
},
_createItems: function(items) {
var self = this;
return BI.map(items, function(index, item) {
return BI.extend(item, {
type: "bi.multi_select_item", // 节点采用复选节点展示
selected: item.done, // 已完成的todo项置为选中状态
disabled: item.done, // 已完成的todo项置为灰化状态
listeners: [
{ // 为每个todo项添加"EVENT_CHANGE"事件监听,触发组件自身"EVENT_CHANGE"事件
eventName: "EVENT_CHANGE",
action: function(v) {
self.fireEvent("EVENT_CHANGE", v);
}
}
]
});
});
},
_setCount: function(count) {
this.count.setText(count);
},
populate: function(items) {
this.list.populate(this._createItems(items));
this._setCount(items.length);
}
});
BI.shortcut("my.todolist.list", List);
})();

101
src/modules/list/list.ts

@ -0,0 +1,101 @@
import { Label, VerticalLayout } from 'fineui';
import { shortcut } from "../../core/typescript/decorator";
import "./list.less";
/**
* todo项列表
*/
@shortcut()
export class List extends BI.Widget {
public static xtype = "my.todolist.list";
private count: Label;
private list: VerticalLayout;
public props = {
// 指定组件的className
baseCls: "my-todolist-list",
text: "正在进行",
items: [],
}
public render() {
const { text, items } = this.options;
return {
type: BI.VerticalLayout.xtype,
items: [
{
el: {
type: BI.VerticalAdaptLayout.xtype,
height: 40,
items: [
{
type: BI.Label.xtype,
cls: "my-todolist-list-text",
textAlign: "left",
text,
width: 580,
}, {
type: BI.CenterAdaptLayout.xtype,
cls: "my-todolist-list-count-container",
width: 20,
height: 20,
items: [
{
el: {
type: BI.Label.xtype,
ref: (_ref: Label) => {
this.count = _ref;
},
text: 0,
},
},
],
},
],
},
}, {
// 用bi.vertical布局作为列表项的容器.
type: BI.VerticalLayout.xtype,
vgap: 10,
ref: (_ref: VerticalLayout) => {
this.list = _ref;
},
items: this.createItems(items),
},
],
};
}
private createItems(items: Item[]) {
return items.map(item => {
return BI.extend(item, {
type: BI.MultiSelectItem.xtype, // 节点采用复选节点展示
selected: item.done, // 已完成的todo项置为选中状态
disabled: item.done, // 已完成的todo项置为灰化状态
listeners: [
{ // 为每个todo项添加"EVENT_CHANGE"事件监听,触发组件自身"EVENT_CHANGE"事
eventName: "EVENT_CHANGE",
action: (v: any) => {
this.fireEvent("EVENT_CHANGE", v);
},
},
],
});
})
}
private setCount(count: number) {
this.count.setText(`${count}`);
}
public populate(items: []) {
this.list.populate(this.createItems(items));
this.setCount(items.length);
}
}
interface Item {
done: boolean,
}

116
src/modules/main.js

@ -1,113 +1,113 @@
!(function() {
/**
import { shortcut } from "../core/javascript/decorator";
import { ToDoListHeader } from "./header/header";
import { List } from "./list/list";
import "./main.less";
/**
* todolist 组件
*/
var ToDoList = BI.inherit(BI.Widget, {
@shortcut()
export class ToDoList extends BI.Widget {
static xtype = "my.todolist";
props: {
baseCls: "fine-to-do-list"
},
props = {
baseCls: "fine-to-do-list",
}
// 生命周期函数,在组件创建前
beforeCreate: function() {
beforeCreate() {
// 初始化存储数据
this.list = localStorage.getItem("fine-todolist") ? JSON.parse(localStorage.getItem("fine-todolist")) : [];
},
}
render: function() {
var self = this, o = this.options;
render() {
return {
type: "bi.vtape", // vtape布局,顶部高度固定,下部分列表占满高度
type: BI.VTapeLayout.xtype, // vtape布局,顶部高度固定,下部分列表占满高度
items: [
{
el: {
type: "my.todolist.header", // 顶部组件
type: ToDoListHeader.xtype, // 顶部组件
listeners: [
{ // 监听组件的EVENT_ADD事件,新建todo项
eventName: "EVENT_ADD",
action: function(v) {
self.addToDo(v);
}
}
action: v => {
this.addToDo(v);
},
},
],
height: 40
height: 40,
},
height: 40
height: 40,
}, {
type: "bi.horizontal_auto", // 水平居中布局
type: BI.HorizontalAutoLayout.xtype, // 水平居中布局
cls: "my-todolist-background", // 添加className
items: [
{
el: {
type: "my.todolist.list", // need todo项列表
ref: function(_ref) {
self.todolist = _ref;
type: List.xtype, // need todo项列表
ref: _ref => {
this.todolist = _ref;
},
items: this._getNeedTodoList(),
text: "正在进行",
listeners: [
{ // 监听EVENT_CHANGE事件,完成某一项todo
eventName: "EVENT_CHANGE",
action: function(v) {
self.finishTodo(v);
}
}
action: v => {
this.finishTodo(v);
},
},
],
width: 600
}
width: 600,
},
}, {
el: {
type: "my.todolist.list", // 已经完成的todo项列表
type: List.xtype, // 已经完成的todo项列表
text: "已经完成",
items: this._getAlreadyDoneList(),
ref: function(_ref) {
self.donelist = _ref;
ref: _ref => {
this.donelist = _ref;
},
width: 600,
},
width: 600
}
}
]
}
]
};
},
],
}],
};
}
_updateLocalStorage: function() {
_updateLocalStorage() {
localStorage.setItem("fine-todolist", JSON.stringify(this.list));
},
}
_getNeedTodoList: function() {
return BI.filter(this.list, function(index, item) {
return !item.done;
});
},
_getNeedTodoList() {
return BI.filter(this.list, (index, item) => !item.done);
}
_getAlreadyDoneList: function() {
return BI.filter(this.list, function(index, item) {
return item.done;
});
},
_getAlreadyDoneList() {
return BI.filter(this.list, (index, item) => item.done);
}
/**
* 添加todo项
* @param text todo项的内容
*/
addToDo: function(text) {
addToDo(text) {
this.list.push({
value: BI.UUID(),
text: text,
done: false
text,
done: false,
});
this.todolist.populate(this._getNeedTodoList());
this._updateLocalStorage();
},
}
/**
* 完成某一项todo
* @param v todo项的value
*/
finishTodo: function(v) {
BI.some(this.list, function(index, item) {
finishTodo(v) {
BI.some(this.list, (index, item) => {
if (item.value === v) {
item.done = true;
}
@ -116,6 +116,4 @@
this.donelist.populate(this._getAlreadyDoneList());
this._updateLocalStorage();
}
});
BI.shortcut("my.todolist", ToDoList);
})();
}

10
src/types/globals.d.ts vendored

@ -0,0 +1,10 @@
interface Obj {
[key: string]: any;
}
declare let BI: Obj & import('fineui').BI;
declare const Fix: Obj;
declare interface String {
replaceAll(regx: string | RegExp, callback: (str: string) => void): string;
}

7
tsconfig.json

@ -0,0 +1,7 @@
{
"extends": "@fui/typescript-configs/application.json",
"compilerOptions": {
"strict": false,
"allowJs": true,
},
}

9
webpack/dirs.js

@ -0,0 +1,9 @@
const path = require("path");
module.exports = {
DEST: path.resolve(__dirname, "../dist"),
NODE_MODULES: path.resolve(__dirname, "../node_modules"),
PRIVATE: path.resolve(__dirname, "../private"),
BABEL_CONFIG: path.resolve(__dirname, "../babel.config.js"),
IE8_BABEL_CONFIG: path.resolve(__dirname, "../babel.config.ie8.js"),
SRC: path.resolve(__dirname, "../src"),
};

63
webpack/webpack.common.js

@ -0,0 +1,63 @@
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const autoprefixer = require("autoprefixer");
const dirs = require("./dirs");
module.exports = {
entry: {
bundle: [
"./src/index.js",
],
},
resolve: {
mainFields: ["module", "main"],
extensions: [".js", ".ts"],
},
stats: {
children: false,
modules: false,
},
module: {
rules: [
{
test: /\.(js|ts)$/,
include: [dirs.NODE_MODULES, dirs.SRC],
use: [{
loader: "babel-loader",
options: {
configFile: dirs.BABEL_CONFIG,
},
}, {
loader: "source-map-loader",
options: {
enforce: "pre",
},
}],
},
{
test: /\.(css|less)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
url: false,
},
},
{
loader: "postcss-loader",
options: {
plugins: [autoprefixer],
},
},
{
loader: "less-loader",
options: {
relativeUrls: false,
},
},
],
},
],
},
};

53
webpack/webpack.dev.js

@ -0,0 +1,53 @@
const merge = require("webpack-merge");
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const dirs = require("./dirs");
const common = require("./webpack.common.js");
module.exports = merge(common, {
devtool: "eval-source-map",
entry: {
},
output: {
path: dirs.DEST,
filename: "[name].[contenthash].js",
},
devServer: {
open: true,
contentBase: path.join(__dirname, ".."),
port: 9002,
liveReload: true,
},
plugins: [
new ForkTsCheckerWebpackPlugin({
}),
new MiniCssExtractPlugin({
path: dirs.DEST,
filename: "[contenthash].css",
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../index.html"),
chunks: ["bundle"],
chunksSortMode: "manual",
nodeModules: path.resolve(__dirname, "../node_modules"),
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require("cssnano"),
cssProcessorPluginOptions: {
preset: ["default", {
discardComments: {
removeAll: true,
},
normalizeUnicode: false,
}],
},
canPrint: true,
}),
],
});

60
webpack/webpack.prod.js

@ -0,0 +1,60 @@
const webpack = require("webpack");
const merge = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const dirs = require("./dirs");
const common = require("./webpack.common.js");
module.exports = merge.smart(common, {
mode: "production",
optimization: {
minimizer: [
new UglifyJsPlugin({
parallel: true,
sourceMap: true,
uglifyOptions: {
ie8: true,
output: {
comments: false,
},
},
}),
],
},
devtool: "hidden-source-map",
output: {
path: dirs.DEST,
filename: "bundle.js",
},
plugins: [
new ForkTsCheckerWebpackPlugin({
}),
new MiniCssExtractPlugin({
path: dirs.DEST,
filename: "bundle.css",
}),
new webpack.BannerPlugin({
banner: `time: ${new Date().toLocaleString()}`,
}),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require("cssnano"),
cssProcessorPluginOptions: {
preset: ["default", {
discardComments: {
removeAll: true,
},
normalizeUnicode: false,
}],
},
canPrint: true,
}),
],
});
Loading…
Cancel
Save