Skip to content

Commit

Permalink
fix: module-replace-plugin not work for new created module
Browse files Browse the repository at this point in the history
  • Loading branch information
liximomo committed Feb 17, 2020
1 parent 4f8b589 commit 63d7730
Show file tree
Hide file tree
Showing 50 changed files with 843 additions and 197 deletions.
23 changes: 17 additions & 6 deletions packages/core/lib/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,28 @@ const react_1 = __importStar(require("react"));
const react_fs_1 = require("@shuvi/react-fs");
const FileNode_1 = __importDefault(require("./components/FileNode"));
const Bootstrap_1 = __importDefault(require("./components/Bootstrap"));
const store_1 = require("./store");
const FilePriorityFile_1 = __importDefault(require("./components/FilePriorityFile"));
const store_1 = require("./models/store");
function App(props) {
const files = store_1.useStore(state => state.files);
const bootstrapFilePath = store_1.useStore(state => state.bootstrapFilePath);
const routesSource = store_1.useStore(state => state.routesSource);
const files = store_1.useSelector(state => state.extraFiles);
const bootstrap = store_1.useSelector(state => state.bootstrapModule);
const app = store_1.useSelector(state => ({
fallbackFile: state.appModuleFallback,
lookupFiles: state.appModuleLookups
}));
const document = store_1.useSelector(state => ({
fallbackFile: state.documentModuleFallback,
lookupFiles: state.documentModuleLookups
}));
const routesContent = store_1.useSelector(state => state.routesContent);
react_1.useEffect(() => {
props.onDidUpdate();
});
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(Bootstrap_1.default, { file: bootstrapFilePath }),
react_1.default.createElement(react_fs_1.File, { name: "routes.js", content: routesSource }),
react_1.default.createElement(Bootstrap_1.default, { module: bootstrap }),
react_1.default.createElement(FilePriorityFile_1.default, Object.assign({ name: "app.js" }, app)),
react_1.default.createElement(FilePriorityFile_1.default, Object.assign({ name: "document.js" }, document)),
react_1.default.createElement(react_fs_1.File, { name: "routes.js", content: routesContent }),
files.map(file => (react_1.default.createElement(FileNode_1.default, { key: file.name, file: file })))));
}
class AppContainer extends react_1.default.Component {
Expand Down
22 changes: 13 additions & 9 deletions packages/core/lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const mobx_react_1 = require("mobx-react");
const react_fs_1 = __importDefault(require("@shuvi/react-fs"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const App_1 = __importDefault(require("./App"));
const paths_1 = require("./paths");
const store_1 = require("./store");
const store_1 = require("./models/store");
const Base_1 = require("./components/Base");
const utils_1 = require("./utils");
class AppCoreImpl {
Expand All @@ -41,17 +42,19 @@ class AppCoreImpl {
getPublicUrlPath(buildPath) {
return utils_1.joinPath(this.config.publicPath, buildPath);
}
addSelectorFile(path, selectFileList, fallbackFile) {
store_1.addSelectorFile(path, selectFileList, fallbackFile);
setBootstrapModule(module) {
store_1.store.bootstrapModule = module;
}
addTemplateFile(path, templateFile, data = {}) {
store_1.addTemplateFile(path, templateFile, data);
setAppModule(lookups, fallback) {
store_1.store.appModuleFallback = fallback;
store_1.store.appModuleLookups = lookups;
}
addFile(path, { content }) {
store_1.addFile(path, content);
setDocumentModule(lookups, fallback) {
store_1.store.documentModuleFallback = fallback;
store_1.store.documentModuleLookups = lookups;
}
setRoutesSource(content) {
store_1.setRoutesSource(content);
store_1.store.routesContent = content;
}
waitUntilBuild() {
return new Promise(resolve => {
Expand All @@ -60,7 +63,6 @@ class AppCoreImpl {
}
build(options) {
return __awaiter(this, void 0, void 0, function* () {
store_1.initBootstrap({ bootstrapFilePath: options.bootstrapFilePath });
yield fs_extra_1.default.emptyDir(this.paths.appDir);
return new Promise(resolve => {
react_fs_1.default.render(react_1.default.createElement(App_1.default, { onDidUpdate: this._onBuildDone.bind(this) }), this.paths.appDir, () => {
Expand All @@ -71,12 +73,14 @@ class AppCoreImpl {
}
buildOnce(options) {
return __awaiter(this, void 0, void 0, function* () {
mobx_react_1.useStaticRendering(true);
Base_1.swtichOffLifeCycle();
try {
yield this.build(options);
}
finally {
Base_1.swtichOnLifeCycle();
mobx_react_1.useStaticRendering(false);
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/lib/components/Bootstrap.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BaseComponent } from "./Base";
interface Props {
file: string;
module: string;
}
export default class Bootstrap extends BaseComponent<Props> {
render(): JSX.Element;
Expand Down
6 changes: 3 additions & 3 deletions packages/core/lib/components/Bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const FileTemplate_1 = __importDefault(require("./FileTemplate"));
const FileTemplateFile_1 = __importDefault(require("./FileTemplateFile"));
const Base_1 = require("./Base");
class Bootstrap extends Base_1.BaseComponent {
render() {
const { file } = this.props;
return (react_1.default.createElement(FileTemplate_1.default, { name: "bootstrap.js", template: `export * from "${file}"` }));
const { module } = this.props;
return (react_1.default.createElement(FileTemplateFile_1.default, { name: "bootstrap.js", template: `export * from "${module}"` }));
}
}
exports.default = Bootstrap;
2 changes: 1 addition & 1 deletion packages/core/lib/components/FileNode.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FileNode as IFileNode } from "@shuvi/types/core";
import { BaseComponent } from "./base";
import { FileNode as IFileNode } from "../models/files";
interface Props {
file: IFileNode;
}
Expand Down
40 changes: 14 additions & 26 deletions packages/core/lib/components/FileNode.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,42 @@
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const react_fs_1 = require("@shuvi/react-fs");
const FileTemplate_1 = __importDefault(require("./FileTemplate"));
const FileSelector_1 = __importDefault(require("./FileSelector"));
const FileTemplateFile_1 = __importDefault(require("./FileTemplateFile"));
const FilePriorityFile_1 = __importDefault(require("./FilePriorityFile"));
const base_1 = require("./base");
const files_1 = require("../models/files");
class FileNode extends base_1.BaseComponent {
constructor(props) {
super(props);
this._renderNode = this._renderNode.bind(this);
this._renderFile = this._renderFile.bind(this);
}
_renderFile(file) {
const { type } = file, props = __rest(file, ["type"]);
let Comp;
switch (type) {
case "template":
Comp = FileTemplate_1.default;
break;
case "selector":
Comp = FileSelector_1.default;
break;
default:
Comp = react_fs_1.File;
if (files_1.isTemplateFile(file)) {
Comp = FileTemplateFile_1.default;
}
else if (files_1.isPriorityFile(file)) {
Comp = FilePriorityFile_1.default;
}
else {
Comp = react_fs_1.File;
}
return react_1.default.createElement(Comp, Object.assign({}, props));
return react_1.default.createElement(Comp, Object.assign({}, file));
}
_renderDir(dir) {
var _a;
return (react_1.default.createElement(react_fs_1.Dir, { name: dir.name }, (_a = dir.children) === null || _a === void 0 ? void 0 : _a.map(node => this._renderNode(node))));
}
_renderNode(node) {
if (node.$$type === "dir") {
if (files_1.isDir(node)) {
return this._renderDir(node);
}
else if (node.$$type === "file") {
else if (files_1.isFile(node)) {
return this._renderFile(node);
}
return null;
Expand Down
24 changes: 24 additions & 0 deletions packages/core/lib/components/FilePriorityFile.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { WatchEvent } from "@shuvi/utils/lib/fileWatcher";
import { BaseComponent } from "./Base";
export interface Props {
name: string;
lookupFiles: string[];
fallbackFile: string;
}
interface State {
file: string;
}
export default class FileSelector extends BaseComponent<Props, State> {
private _watcherHandle;
private _knownFiles;
constructor(props: Props);
_onFilesChange({ removals, changes }: WatchEvent): void;
_destoryWatcher(): void;
_createWatcher(): void;
componentDidMount(): void;
componentWillUnmount(): void;
componentDidUpdate(prevProps: Props): void;
shouldComponentUpdate(nextProps: Props, nextState: State): boolean;
render(): JSX.Element;
}
export {};
96 changes: 96 additions & 0 deletions packages/core/lib/components/FilePriorityFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const react_fs_1 = require("@shuvi/react-fs");
const fileWatcher_1 = require("@shuvi/utils/lib/fileWatcher");
const fs_extra_1 = __importDefault(require("fs-extra"));
const utils_1 = require("../utils");
const Base_1 = require("./Base");
function findFirstExistedFile(files) {
for (let index = 0; index < files.length; index++) {
const file = files[index];
if (fs_extra_1.default.existsSync(file)) {
return file;
}
}
return null;
}
class FileSelector extends Base_1.BaseComponent {
constructor(props) {
super(props);
this._knownFiles = new Map();
const file = findFirstExistedFile(props.lookupFiles);
let selectedFile;
if (file) {
selectedFile = file;
this._knownFiles.set(file, true);
}
else {
selectedFile = props.fallbackFile;
}
this.state = {
file: selectedFile
};
this._onFilesChange = this._onFilesChange.bind(this);
}
_onFilesChange({ removals, changes }) {
for (let index = 0; index < changes.length; index++) {
const existed = changes[index];
this._knownFiles.set(existed, true);
}
for (let index = 0; index < removals.length; index++) {
const removed = removals[index];
this._knownFiles.delete(removed);
}
const { lookupFiles, fallbackFile } = this.props;
let selectedFile = fallbackFile;
for (let index = 0; index < lookupFiles.length; index++) {
const file = lookupFiles[index];
if (this._knownFiles.has(file)) {
selectedFile = file;
break;
}
}
if (selectedFile !== this.state.file) {
this.setState({
file: selectedFile
});
}
}
_destoryWatcher() {
if (this._watcherHandle) {
this._watcherHandle();
}
}
_createWatcher() {
this._destoryWatcher();
if (this.props.lookupFiles.length) {
this._watcherHandle = fileWatcher_1.watch({ files: this.props.lookupFiles }, this._onFilesChange);
}
}
componentDidMount() {
this._createWatcher();
}
componentWillUnmount() {
this._destoryWatcher();
}
componentDidUpdate(prevProps) {
if (!utils_1.arrayEqual(prevProps.lookupFiles, this.props.lookupFiles)) {
this._createWatcher();
}
}
shouldComponentUpdate(nextProps, nextState) {
return (this.state !== nextState ||
this.props.fallbackFile !== nextProps.fallbackFile ||
!utils_1.arrayEqual(this.props.lookupFiles, nextProps.lookupFiles));
}
render() {
const { name } = this.props;
const { file } = this.state;
return (react_1.default.createElement(react_fs_1.File, { name: name, content: `module.exports = require("${file}");` }));
}
}
exports.default = FileSelector;
14 changes: 14 additions & 0 deletions packages/core/lib/components/FileTemplateFile.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { TemplateData } from "@shuvi/types/core";
import { BaseComponent } from "./Base";
export interface Props {
name: string;
templateFile?: string;
template?: string;
data?: TemplateData;
}
export default class FileTemplate extends BaseComponent<Props> {
private _compileTemplate;
private _readFile;
private _renderTemplate;
render(): JSX.Element | null;
}
35 changes: 35 additions & 0 deletions packages/core/lib/components/FileTemplateFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const react_fs_1 = require("@shuvi/react-fs");
const fs_extra_1 = __importDefault(require("fs-extra"));
const handlebars_1 = __importDefault(require("handlebars"));
const utils_1 = require("../utils");
const Base_1 = require("./Base");
class FileTemplate extends Base_1.BaseComponent {
constructor() {
super(...arguments);
this._compileTemplate = utils_1.memoizeOne((template) => handlebars_1.default.compile(template));
this._readFile = utils_1.memoizeOne((path) => fs_extra_1.default.readFileSync(path, "utf8"));
}
_renderTemplate(template) {
const templateFn = this._compileTemplate(template);
const content = templateFn(this.props.data || {});
return react_1.default.createElement(react_fs_1.File, { name: this.props.name, content: content });
}
render() {
const { templateFile, template } = this.props;
if (template) {
return this._renderTemplate(template);
}
if (templateFile) {
const tmplContent = this._readFile(templateFile);
return this._renderTemplate(tmplContent);
}
return null;
}
}
exports.default = FileTemplate;
12 changes: 12 additions & 0 deletions packages/core/lib/models/ModelApp.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { FileNode, File } from "./files/FileNode";
export declare class ModelApp {
bootstrapModule: string;
appModuleFallback: string;
appModuleLookups: string[];
documentModuleFallback: string;
documentModuleLookups: string[];
routesContent: string;
extraFiles: FileNode[];
addFile(file: File, dir?: string): void;
removeFile(path: string): void;
}
Loading

0 comments on commit 63d7730

Please sign in to comment.